delphi中的线程安全

时间:2013-07-17 16:22:03

标签: multithreading delphi 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;

谢谢。

3 个答案:

答案 0 :(得分: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;

请注意使用 TCriticalSection CriticalX )的单个实例来序列化对数据成员 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;

我希望这有帮助!

答案 1 :(得分:5)

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

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

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

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

答案 2 :(得分: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;

谢谢大家的帮助。