7

スレッド内のいくつかのビジュアル コンポーネントを修正および変更する必要がありますが、ご存じのとおり、これを行うのは安全ではありません。

私の質問は、完全にスレッドセーフなコードを書く方法ですか? 可能です?もしそうなら、簡単な例を教えてください。

スレッドセーフではない私のコード:

type
  tMyWorkerThread = class(TThread)
      public
         procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure tMyWorkerThread.Execute;
begin
  //codes
  //working with visual components
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyWorkerThread.Create(false);
end;

ありがとうございました。

4

3 に答える 3

10

Delphi でスレッド セーフなコードを記述するには、他の言語で行うような基本的な注意が必要です。これは、競合状態に対処することを意味します。異なるスレッドが同じデータにアクセスすると、競合状態が発生します。これに対処する良い方法は、TCriticalSectionのインスタンスを宣言し、その中に危険なコードをラップすることです。

以下のコードは、仮説により、競合状態を持つプロパティのゲッターとセッターを示しています。

constructor TMyThread.Create;
begin
  CriticalX := TCriticalSection.Create;
end;

destructor TMyThread.Destroy; override;
begin
  FreeAndNil(CriticalX);
end;

function TMyThread.GetX: string;
begin
  CriticalX.Enter;
  try
    Result := FX;
  finally
    CriticalX.Leave;
  end;
end;

procedure TMyThread.SetX(const value: string);
begin
  CriticalX.Enter;
  try
    FX := Value;
  finally
    CriticalX.Leave;
  end;
end;

TCriticalSection ( CriticalX )の 1 つのインスタンスを使用して、データ メンバーFXへのアクセスをシリアル化していることに注意してください。

ただし、Delphi には追加の考慮事項があります。VCL はスレッド セーフではないため、VCL の競合状態を回避するには、画面の変更が発生するすべての操作をメイン スレッドで実行する必要があります。Synchronizeメソッド内でそのようなコードを呼び出すことで、これを取得できます。上記のクラスを考慮すると、次のようにする必要があります。

procedure TMyThread.ShowX;
begin
  Synchronize(SyncShowX);
end;

procedure TMyThread.SyncShowX;
begin
  ShowMessage(IntToStr(FX));
end;

Delphi 2010以降を使用している場合は、匿名メソッドを利用する簡単な方法があります。

procedure TMyThread.ShowX;
begin
  Synchronize(procedure begin
    ShowMessage(IntToStr(FX));
  end);
end;

これが役立つことを願っています!

于 2013-07-17T18:00:39.557 に答える
5

メイン VCL スレッドからのみ VCL オブジェクトにアクセスする必要があります。

一部の読み取りメソッド(プロパティ ゲッター)は、実際には他のスレッドから機能しますが、特定の Delphi ビルドの VCL ソースを読み取る前に、それを証明する必要があります。または使用しないでください。

PS: Synchronize メソッドは、メイン VCL スレッドで指定されたプロシージャを実行し、呼び出し元スレッドを一時停止します。これにより、メイン スレッドもブロックされている場合、デッドロックが発生する可能性があります。

続きを読む:(実際には、いくつかのリンクをリストするためにこの回答を作成しています)

于 2013-07-17T17:15:19.767 に答える
0

私の問題は解決しましたSynchronize!

type
  tMyWorkerThread = class(TThread)
      public
         procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure tMyWorkerThread.Execute;
begin

  //codes that takes long time
  Synchronize(procedure begin
     //working with visual components
  end
  );

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyWorkerThread.Create(false);
end;

助けてくれてありがとう。

于 2013-07-18T20:18:53.043 に答える