Управление потоками в программировании на Delphi может быть непростой задачей, особенно при необходимости паузы и запуска потока. Вопрос пользователя касается именно этой проблемы: как безопасно управлять потоком TThread, используя объект, созданный на главной форме программы, и кнопки для старта и остановки потока.
Проблема
Пользователь рассматривает несколько вариантов управления потоком в своем приложении:
Терминирование и освобождение потока при клике на "стоп" и создание нового при клике на "старт".
Использование функции Sleep для задержки потока, что не является предпочтительным вариантом.
Использование булевой свойства для определения паузы потока, и выполнение кода в Execute только при его ложном значении.
Пользователь склоняется к третьему варианту и интересуется, будет ли установка булевой свойства на объекте TThread из главного потока безопасной с точки зрения многопоточности.
Решение
В более новых версиях Delphi прямая пауза/возобновление потоков не рекомендуется, так как концепция была изначально неверной. Вместо этого следует использовать сигнализированные события, например, TEvent. Это позволяет более гибко и безопасно управлять потоками.
Пример кода
type
TMyThread = class(TThread)
private
FRunEvent, FTermEvent: TEvent;
FWaitEvents: THandleObjectArray;
procedure CheckPause;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Pause;
procedure Unpause;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FRunEvent := TEvent.Create(nil, True, True, '');
FTermEvent := TEvent.Create(nil, True, False, '');
SetLength(FWaitEvents, 2);
FWaitEvents[0] := FRunEvent;
FWaitEvents[1] := FTermEvent;
end;
destructor TMyThread.Destroy;
begin
FRunEvent.Free;
FTermEvent.Free;
inherited;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
// выполнение работы...
CheckPause;
// еще выполнение работы...
CheckPause;
// и еще...
CheckPause;
// ...
end;
end;
procedure TMyThread.TerminatedSet;
begin
FTermEvent.SetEvent;
end;
procedure TMyThread.CheckPause;
var
SignaledEvent: THandleObject;
begin
while not Terminated do
begin
case TEvent.WaitForMultiple(FWaitEvents, INFINITE, False, SignaledEvent) of
wrSignaled: begin
if SignaledEvent = FRunEvent then Exit;
Break;
end;
wrIOCompletion: begin
// перепробовать
end;
wrError: begin
RaiseLastOSError;
end;
end;
SysUtils.Abort;
end;
end;
procedure TMyThread.Pause;
begin
FRunEvent.ResetEvent;
end;
procedure TMyThread.Unpause;
begin
FRunEvent.SetEvent;
end;
Обсуждение
В примере выше используется класс TMyThread, который наследуется от TThread и добавляет механизм синхронизации с помощью событий FRunEvent и FTermEvent. Метод CheckPause ожидает сигнала от одного из событий, что позволяет паузировать и возобновлять выполнение потока без использования булевых свойств, что является более безопасным и надежным способом управления потоками.
Заключение
Использование сигнализированных событий для управления потоками TThread в Delphi является предпочтительным методом. Это позволяет избежать сложностей, связанных с синхронизацией и безопасностью данных при использовании булевых свойств и функций паузы/возобновления, которые не поддерживаются в современных версиях Delphi. Приведенный выше пример кода демонстрирует, как можно реализовать такую систему управления потоком, используя Object Pascal.
Управление потоками в Delphi с использованием событий для паузы, запуска и синхронизации.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.