Структура BeginThread - Delphi - PullRequest
       55

Структура BeginThread - Delphi

5 голосов
/ 25 января 2011

У меня есть почти готовое приложение, и следующая функция, которую я хочу реализовать, - это многопоточность.Я решил использовать BeginThread (), хотя знаю о TThread в Delphi.Проблема, с которой я сталкиваюсь, заключается в структуре вызова BeginThread ().Обычно строка в программе, которая будет вызывать функцию, к которой я хочу подключиться, имеет вид

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);

op - целое число.

Строка, для которой я отключил ее для создания потока:

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x);

Из небольшого количества информации, которую я могу найти о том, как на самом деле использовать BeginThread (), это должнобудь хорошим вызовом, однако при компиляции все, что я получаю, - это ошибки компилятора относительно структуры моих параметров оператора BeginThread ().

РЕДАКТИРОВАТЬ ИНФОРМАЦИЮ.

Текущая процедура, которая вызывает CompareFiles:

procedure TForm1.Panel29Click(Sender: TObject);
var
op,x : integer;

begin
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then
        begin
          op := 3;
          if RadioButton7.Checked = True then op := 0;
          if RadioButton3.Checked = True then op := 1;
          if RadioButton4.Checked = True then op := 2;
          if RadioButton5.Checked = True then op := 3;
          if RadioButton6.Checked = True then op := 4;
          CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
        end;
end;

Если бы я использовал TThread, как предложили несколько человек, и как показано Робом ниже, я запутался в том, как) Я бы передал op, Edit3 / 4.Text и StringGrid2 в CompareFiles.Догадываясь на примере TThread, который я видел, я решил заменить приведенный выше код на TCompareFilesThread.Execute, а затем поместить текущий код из Panel29 в TCompareFilesThread.Create, а затем добавить

FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;

к этому

FEdit3Text := Form1.Edit3.Text;
FEdit4Text := Form1.Edit4.Text;
FGrid := Form1.StringGrid2;

Но у меня есть это ноющее чувство, которое совершенно не в порядке.

1 Ответ

14 голосов
/ 25 января 2011

Это совсем не способ использования BeginThread.Эта функция ожидает указатель на функцию, которая принимает один параметр, но функция, которую вы пытаетесь вызвать, хочет четыре.Единственный параметр, который вы указываете BeginThread для передачи в потоковую процедуру, - это строка, но вы, очевидно, надеетесь, что какое-то волшебство превратит эту строку символов в значения, которые содержат эти переменные.

Это не так, как работает Delphi, и даже для языков, которые могут делать что-то подобное, обычно не рекомендуется на самом деле делать это.

Для передачи нескольких параметровна BeginThread, определите запись со всеми необходимыми значениями, а также определите указатель записи:

type
  PCompareFilesParams = ^TCompareFilesParams;
  TCompareFilesParams = record
    Edit3Text,
    Edit4Text: string;
    Grid: TStringGrid;
    Op: Integer;
  end;

Измените CompareFiles, чтобы принять указатель на эту запись:

function CompareFiles(Params: PCompareFilesParams): Integer;

Чтобы запустить поток, вам нужно выделить экземпляр этой записи и заполнить ее поля:

var
  Params: PCompareFilesParams;
begin
  New(Params);
  Params.Edit3Text := Edit3.Text;
  Params.Edit4Text := Edit4.Text;
  Params.Grid := StringGrid2;
  Params.Op := op;
  BeginThread(nil, 0, @CompareFiles, Params, 0, x);

Реализуйте CompareFiles так, чтобы запись освободилась перед потоком.прекращается:

function CompareFiles(Params: PCompareFilesParams): Integer;
begin
  try
    // <Normal implementation goes here.>
  finally
    Dispose(Params);
  end;
end;

Вы можете сделать все это намного проще, если просто используете TThread.Вы можете сделать так, чтобы ваш класс-потомок имел столько параметров, сколько вы хотите в его конструкторе, так что вам не придется возиться с динамическим размещением и освобождением специальной записи.

type
  TCompareFilesThread = class(TThread)
  private
    FEdit3Text,
    FEdit4Text: string;
    FGrid: TStringGrid;
    FOp: Integer;
    procedure Execute; override;
  public
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer);
    property ReturnValue;
  end;

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
  FEdit3Text := Edit3Text;
  FEdit4Text := Edit4Text;
  FGrid := Grid;
  FOp := Op;
end;

procedure TCompareFilesThread.Execute;
begin
  ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp);
end;

Вместо вызова BeginThread, вы просто создаете экземпляр класса и запускаете его:

var
  ThreadRef: TThread;


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op);

Существует еще кое-что для использования потоков, например, знание, когда поток завершил работу, но я думаю, у вас достаточно для начала работы.Последнее, что следует остерегаться, это то, что TStringGrid является элементом управления VCL.Вы не должны ничего делать с ним из этой новой темы, которую вы создаете (независимо от того, как вы ее создали).Все, что вы делаете с контролем сетки, должно быть сделано из основного потока.Используйте TThread.Synchronize и TThread.Queue, чтобы перенести любые операции VCL в основной поток.Поток сравнения файлов будет ожидать завершения синхронизированной операции, но будет продолжать работу, не дожидаясь завершения операции в очереди.

...