delphi中的线程安全

Sky*_*Sky 6 delphi multithreading thread-safety delphi-2010

我必须修改和更改一个线程中的一些可视组件,因为你知道这样做是不安全的.

我的问题是如何编写完全线程安全的代码?有可能的?如果是的话那么请你举个简单的例子吗?

我的代码不是线程安全的:

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;
Run Code Online (Sandbox Code Playgroud)

谢谢.

Ale*_*xSC 9

在Delphi中编写线程安全代码涉及到任何其他语言的基本护理,这意味着要处理竞争条件.当不同的线程访问相同的数据时会发生竞争条件.处理这个问题的一个好方法是声明一个TCriticalSection实例并将危险代码包装在其中.

下面的代码显示了一个getter和一个属性的setter,通过hypotesis,有一个竞争条件.

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;
Run Code Online (Sandbox Code Playgroud)

请注意使用单个TCriticalSection(CriticalX)实例来序列化对数据成员FX的访问.

但是,对于Delphi,您有一个额外的考虑因素!VCL不是线程安全的,因此为了避免VCL竞争条件,任何导致屏幕更改的操作都必须在主线程中运行.你可以通过在Synchronize方法中调用这样的代码来实现.考虑到上面的类,你应该做这样的事情:

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

procedure TMyThread.SyncShowX;
begin
  ShowMessage(IntToStr(FX));
end;
Run Code Online (Sandbox Code Playgroud)

如果你有Delphi 2010或更高版本,有一种更简单的方法可以使用匿名方法:

procedure TMyThread.ShowX;
begin
  Synchronize(procedure begin
    ShowMessage(IntToStr(FX));
  end);
end;
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!


Ari*_*The 5

您应该只从主VCL线程访问VCL对象.

一些读取方法(属性获取器)在实践中可以从其他线程开始工作 - 但是您必须事先为特定的Delphi构建读取VCL源代码.或者不使用它.

PS:Synchronize方法在主VCL线程中运行给定的程序,暂停调用程序线程,如果主线程也被阻塞,这可能导致死锁.

阅读更多:(实际上这个答案列出了一些链接)

  • 好清单!Martin Harvey的"Multithreading - Delphi Way"也应该在那里.在我看来,在顶部位置:-D不幸的是[原创](http://www.pergolesi.demon.co.uk/prog/threads/ToC.html)不再存在,但有几个"缓存"副本周围:[Thaddy's](http://thaddy.co.uk/threads/)和[http://web.archive.org/](http://web.archive.org/web/20060305174604/http:/ /www.pergolesi.demon.co.uk/prog/threads/ToC.html)是我所知道的.它也可以通过[Code Central](http://cc.embarcadero.com/item/14809)获得. (2认同)

Sky*_*Sky -2

我的问题解决了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;
Run Code Online (Sandbox Code Playgroud)

谢谢大家对我的帮助。

  • 遗憾的是您会添加并接受自己的答案,而不是告诉您同样事情的其他答案之一。真正打破了 Stack Overflow 的工作流程。 (13认同)