6

ほぼ完成したアプリができました。次に実装したい機能はスレッド化です。delphiのTThreadを認識していますが、BeginThread()を使用することにしました。私が遭遇している問題は、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;

数人の人が提案し、以下のRobが示すように、TThreadを使用する場合、a)op、Edit3/4.TextおよびStringGrid2をCompareFilesに渡す方法に混乱します。私が見たTThreadの例から推測するTCompareFilesThread.Executeと、上記のコードをに置き換えて、Panel29Clickからの現在のコードを入れてからTCompareFilesThread.Create追加すると思いました

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

これに

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

しかし、私は完全にマークから外れているこのしつこい感じを持っています。

4

1 に答える 1

14

を使用する方法はまったくありませんBeginThreadその関数は、 1つのパラメーターを取る関数へのポインターを想定していますが、呼び出そうとしている関数には4つのパラメーターが必要です。スレッドプロシージャに転送するために指定しているパラメータの1つ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操作をメインスレッドにシフトします。ファイル比較スレッドは、同期された操作が完了するのを待ちますが、キューに入れられた操作が完了するのを待たずに実行を続けます。

于 2011-01-25T02:32:42.010 に答える