Потокобезопасный в delphi
Я должен изменить и изменить некоторые визуальные компоненты в потоке, и, как вы знаете,это небезопасно.
У меня вопрос как написать полностью потокобезопасный код? это возможно? если да, то не могли бы вы привести простой пример?
мой код, который не является threadsafe:
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 ответов
написание потокобезопасного кода в 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) для сериализации доступа к элементу данных FX.
однако, с Delphi у вас есть aditional рассмотрение! VCL не является потокобезопасным, поэтому во избежание условий гонки VCL любая операция, которая приводит к экран изменение должен работать в основном потоке. Вы, что, называя такой код внутри синхронизация метод. Учитывая класс выше, вы должны сделать что-то вроде этого:
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;
надеюсь, это поможет!
вы должны получить доступ только к объектам VCL из основного потока VCL.
некоторые методы чтения (геттеры свойств) работают из других потоков на практике, но вы должны доказать это заранее, читая источники VCL для конкретной сборки Delphi. Или не использовать.
PS: метод Synchronize запускает данную процедуру в основном потоке VCL, приостанавливая поток вызывающего абонента, что может привести к взаимоблокировке, если основной поток также был заблокирован.
Read more: (фактически делая этот ответ список некоторых ссылок)
- http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/VCLThreadDemo.shtml
- http://www.drbob42.com/uk-bug/hood-04.htm
- http://delphi.about.com/od/kbthread/a/thread-gui.htm
- лучше ли использовать "синхронизацию" TThread или использовать сообщения окна для IPC между основным и дочерним потоком?
- Delphi 6: точка останова срабатывает на не-VCL поток останавливает основной поток перерисовывает
- http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devwin32/win32_mthreadusemainthread_xml.html
- упрощение кода оболочки потока VCL
- обновление компонента VCL из CreateAnonymousThread
- http://thaddy.co.uk/threads/ - зеркало " многопоточности-Дельфы Путь " Мартином Харви
- http://otl.17slon.com/ - Нью-Делфи подход к резьбонарезной
моя проблема решена с 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;
спасибо всем за помощь мне.