2014-03-12 3 views
1

Когда я прекращаю поток 'srch_slave_thread', устанавливая флаг завершения в true, (srch_slave_thread.terminate), освобождая потоки останавливается на «унаследованной» линии в деструкторе, почему? Это WaitFor, что он зависает? Если я прокомментирую «унаследованный» в деструкторе, поток останавливается и освобождается.Окончание нити (снова ...)

После извлечения «унаследованного» и отладки кода: почему поток вызывает метод DoTerminate после вызова деструктора?

Thank you.

Tsrch_slave_thread = class(TThread) 
private 
    FSW: TStopWatch; 
protected 
    procedure Execute; override; 
public 
    SimpleEvent: TSimpleEvent; 
    procedure DoTerminate; override; 
    ... 
    constructor Create; 
    destructor Destroy; override; 
end; 

Создание события obj. в конструкторе >>

constructor Tsrch_slave_thread.create; 
begin 
    inherited create(true); 
    Fsw := TStopWatch.Create; 
    SimpleEvent := TSimpleEvent.Create; 
end; 

Перепрыгивает сюда после вызова деструктора? >>

procedure Tsrch_slave_thread.DoTerminate; 
begin 
    inherited; 
    self.simpleEvent.SetEvent; 
end; 

Thread висит на наследуется в деструкторе >>

destructor Tsrch_slave_thread.destroy; 
begin 
    self.SimpleEvent.free; 
    inherited; 
end; 

Создать нить здесь >>

function TMaster.th_slvsearch_start: integer; 
begin 
    if not Assigned(Fslave_search_thread) then begin 
    Fslave_search_thread := TFslave_search_thread.create; 
    ... 
    end 
    else begin 
    ... 
    exit; 
    end; 
    with Fslave_search_thread do 
    begin  
    master := self; 
    master_HWND := self.fMsgHandlerHWND; 
    FreeOnTerminate := false; 
    OnTerminate := slvsrch_termination; 
    start;   
    end; 
end; 

останавливая нить начинает здесь >>

procedure TMaster.th_slvsearch_stop; 
begin 
    Fslave_search_thread.Terminate; 
end; 

Тема. Выполнение >>

procedure Tsrch_slave_thread.Execute; 
var 
    text_orig: string; 
    activesearch: integer; 
begin 
    FSW.Start; 
    while not terminated do begin 
    activesearch := master.CMD_LISTCNT; 
    //stopper refresh 
    synchronize(procedure begin   
     with self.master do 
      Fmasternode.text := FmasterDat.MstrName + ' (' + floattostr(Fsw.ElapsedMilliseconds/1000) + 'sec - Searching)'; 
    end); 
    if (SimpleEvent.WaitFor(2000) <> wrTimeOut) or (activesearch <> 1) then break; 
    end; 
    FSW.Stop; 
end; 

OnTerminate обработчик события >>

procedure TMaster.slvsrch_termination(Sender: TObject); 
begin 
    if Assigned(Fslave_search_thread) then 
    begin 
    self.FLastSearchTime := Fslave_search_thread.FSW.ElapsedMilliseconds/1000; 
    Fslave_search_thread.Free; 
    Fslave_search_thread := nil; 
    self.Factive_slv_search := 0; 
    end; 
    ... 
end; 
+0

* «Почему поток перескакивает в метод DoTerminate после вызова деструктора?» * Поскольку кто-то должен сказать, что поток завершается, и если это явно не указано, это деструктор, который устанавливает флаг завершения. – TLama

+0

@TLama, да, но я установил флаг с помощью srch_slave_thread.terminate – grinner

ответ

6

Вы звоните Free на объект потока от его обработчика OnTerminate событий. Это само по себе является ошибкой, потому что вы не можете освободить объект, пока он запускает событие, потому что когда событие возвращается, вы теперь выполняете код в объекте, который был уничтожен.

Но это не ваша непосредственная проблема. Вы заблокировали поток из-за звонка WaitFor в TThread.Destroy. Нить не может закончить, потому что она ждет сама по себе. Стек вызовов на резьбе выглядит следующим образом:

 
Synchronize(CallOnTerminate) 
DoTerminate 
ThreadProc 

Так поток ожидает на главном потоке, чтобы закончить выполнение CallOnTerminate. На основном потоке внутри вашего OnTerminate обработчик - это вызов Free. Это, в свою очередь, приводит к звонку WaitFor. Следовательно, основной поток ожидает завершения потока. Это ваш классический тупик. Нить А, ожидающая на резьбе В, и нить В, ожидающая на резьбе А.

Мораль истории: никогда не вызывайте Free на поток внутри своего обработчика событий OnTerminate.

Раствор, вероятно, чтобы установить FreeOnTerminate к True и в OnTerminate обработчика установить Fslave_search_thread к nil.

+0

Это не первый раз, когда я делаю эту ошибку, но надеюсь, что она была последней. Спасибо. – grinner

+0

Теперь моя проблема в том, что если я закрою приложение, некоторые AV сгенерированы. Ссылка на объект obj является полем другого объекта (TMaster). Когда я закрываю приложение, я освобождаю всех мастеров в цикле. В деструкторе TMaster я устанавливаю флаг завершения потока (если поток был назначен ранее). Что не так с этим? – grinner

+0

ОК. Ну, я думаю, вы делаете SSCCE и публикуете новый вопрос. –

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