2016-07-21 3 views
5

У меня есть объект TThread и хочу, чтобы иметь возможность запускать/останавливать поток на главной форме программы с помощью кнопки. Я искал способы сделать это, и до сих пор у меня есть следующие идеи:«Приостановка» Нить со свойством

  1. Завершить и освободить поток, когда пользователь нажимает кнопку «Стоп» и создает новый при нажатии кнопки «Пуск».
  2. Используйте sleep, чтобы задержать поток (я не хочу этого делать)
  3. Имейте свойство, которое является логическим, чтобы определить, приостановлен ли поток или нет. Код в Execute будет выполняться только в том случае, если это логическое значение false.

Я склоняюсь к # 3. Устанавливает ли логическое свойство объекта TThread из основной формы потокобезопасным?

Какой из этих вариантов, или какой-либо лучшей альтернативы, я должен идти с? Это первый раз, когда я использую нитки, поэтому любая помощь оценивается.

+2

Последние версии Delphi не позволяют приостанавливать/возобновлять потоки, потому что весь дизайн (и концепция) был испорчен. Вам следует избегать попыток сделать это и переключиться на использование сигнальных событий (например, TEvent). См. Различные типы событий в SyncObjs. –

+1

смотри также http://stackoverflow.com/questions/4401171/self-suspending-a-thread-in-delphi-when-its-not-needed-and-safely-resuming – kludg

ответ

9

1.Terminate и Free the thread, когда пользователь нажимает кнопку остановки и создает новую, когда они нажимают кнопку запуска.

Это, безусловно, вариант, если накладные расходы минимальны.

3. Имеет свойство, которое является логическим, чтобы определить, приостановлена ​​ли нить или нет. Код в Execute будет выполняться только в том случае, если это логическое значение false.

Вы могли бы это сделать, но вам нужно будет регулярно проверять это булево, и если он установлен, введите цикл ожидания до тех пор, пока он не будет очищен или поток не будет завершен.

Будет ли установка булевого свойства на объект TThread из основной формы быть потокобезопасной?

Это как потокобезопасная как вызов TThread.Terminate(), который просто устанавливает логическое TThread.Terminated свойства.

Каким из этих вариантов, или любой лучшей альтернативой, я должен пойти?

Я использую опцию # 4 - используя сигнальные события вместо булевых. Например:

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 
    // do some work... 
    CheckPause; 
    // do some more work... 
    CheckPause; 
    // do some more work... 
    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 
     // retry 
     end; 
     wrError: begin 
     RaiseLastOSError; 
    end; 
    end; 
    SysUtils.Abort; 
end; 

procedure TMyThread.Pause; 
begin 
    FRunEvent.ResetEvent; 
end; 

procedure TMyThread.Unpause; 
begin 
    FRunEvent.SetEvent; 
end; 
+0

Remy, что такое 'SysUtils.Abort;' в используемом методе 'CheckPause'. –

+0

Он вызывает исключение «EAbort» для немедленного прекращения потока (поскольку 'Execute()' его не улавливает) в следующий раз вызывается 'CheckPause()' после вызова 'Terminate()'. –

-1

Заканчивать вики для Delphi на запуск и остановка темы здесь: http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads

Это применимо еще в Delphi 7. Это может быть применимо дальше назад, но я не могу подтвердить более ранние версии.

+2

Это комментарий к вопросу, не ответ.Ответы содержат соответствующую информацию здесь, в самой записи, с ссылками, используемыми только для предоставления дополнительной справки. Ответы должны стоять сами по себе, так что они содержат значение, если по какой-либо причине недоступно местоположение вне сайта (перемещено, автономно или что-то еще). Ссылка только ответы не делают этого. –

+2

Добро пожаловать в переполнение стека. Вы не ответили на вопрос. Вопрос запрашивает рекомендацию, но вы пренебрегли ее предоставлением. Пожалуйста, отредактируйте свой ответ, чтобы он обратился к тому, что задает вопрос. –

Смежные вопросы