Writing a thread safe code in Delphi involves the basic care you would have in any other language, which means to deal with race conditions. A race condition happens when different threads access the same data. A good way to deal with that is to declare an instance of TCriticalSection and wrap the dangerous code in it.
The code below shows a getter and a setter of a property that, by hypotesis, has a race condition.
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;
Notice the use of a single instance of TCriticalSection (CriticalX) to serialize the access to the data member FX.
However, with Delphi you have an aditional consideration! VCL is not thread safe, so in order to avoid VCL race conditions, any operation that results in screen changing must run in the main thread. You get that by calling such a code inside a Synchronize method. Considering the class above, you should do something like this:
procedure TMyThread.ShowX;
begin
Synchronize(SyncShowX);
end;
procedure TMyThread.SyncShowX;
begin
ShowMessage(IntToStr(FX));
end;
If you have Delphi 2010 or later, there is an easier way that makes use of anonymous methods:
procedure TMyThread.ShowX;
begin
Synchronize(procedure begin
ShowMessage(IntToStr(FX));
end);
end;
I hope this helps!