2014-06-13 7 views
2

작업자 스레드를 해제 할 때 스레드의 OnTerminate 이벤트 처리기에서 스레드를 해제 할 때 교착 상태가 발생하는 이유는 알 수 없습니다. (TMaster.slvsrch_termination). 스레드 교착 상태에서 동기화하는 대신 postmessage를 사용하여 교착 상태를 방지하기 위해 일부 VCL 컨트롤을 동기화합니다. 스레드의스레드 해방시 교착 상태가 발생했습니다.

procedure Tsrch_slave_thread.Execute; 
var  
    activesearch: integer; 
begin 
    activesearch := 1; 
    FMaster.CMD_SEARCH;    
    FSW.Start; 
    while not terminated do begin 
    postmessage(FDevTree_HWND, WM_STOPPER_REFRESH, trunc(Fsw.ElapsedMilliseconds/1000), integer(FMasterNode));  
    // 
    if (SimpleEvent.WaitFor(SEARCH_DELAY_SEC) <> wrTimeOut) or (activesearch <> 1) then break; 
    activesearch := Fmaster.CMD_LISTCNT; 
    FSW.Stop; 
    end; 
end; 

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

FreeOnTerminate 속성은 false로 설정되어 :

... 
Fslave_search_thread: Tsrch_slave_thread; 
... 
Fslave_search_thread.FreeOnTerminate := false 
Fslave_search_thread.OnTerminate := slvsrch_termination; 
... 

procedure TMaster.slvsrch_termination(Sender: TObject); 
begin 
    ... 
    if Assigned(Fslave_search_thread) then 
    begin 
    Fslave_search_thread.free; //Deadlock, why? 
    Fslave_search_thread := nil; 
    end; 
    ... 
end; 

답변

4

교착 상태가 발생하기 때문에 스레드에서 스레드의 소멸자 기다립니다. 이렇게하려면 WaitFor이 필요합니다. 스레드의 소멸자는 slvsrch_termination에서 호출됩니다. 그 스레드에 대한 OnTerminate 이벤트 처리기입니다. 그리고 OnTerminate 이벤트 핸들러는 Synchronize을 호출하여 호출되기 때문에 주 스레드에서 실행됩니다.

다음은 데드락입니다. 다음과 같이 진행됩니다.

  1. 스레드 Execute 스레드가 종료 코드를 실행합니다.
  2. 스레드 종료 코드가 주 스레드와 동기화됩니다. 이 시점에서 슬레이브 쓰레드는 Synchronize을 호출하여 메인 쓰레드를 기다리고있다.
  3. 주 스레드에서 실행중인 스레드 종료 코드가 슬레이브 스레드를 파괴합니다. 이로 인해 스레드에 WaitFor이 생깁니다. 이제 주 스레드가 슬레이브 스레드에서 대기 중입니다.

2 단계와 3 단계가 교착 상태입니다. 교착 상태를 넘어서


, 그것은 또한 당신이 자신의 OnTerminate 핸들러에서 슬레이브 스레드 인스턴스를 무료로 오류가 발생합니다. 스레드 프로 시저의 코드를보고 :

FreeThread := Thread.FFreeOnTerminate; 
Thread.DoTerminate; 
Thread.FFinished := True; 

귀하의 OnTerminate 핸들러는 DoTerminate에 대한 호출에서 호출됩니다. 반환하면 Thread이 파괴되었지만 코드는 여전히 액세스합니다.

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

inheritedOnTerminate 핸들러를 호출 : 당신의 코드를 더 살펴 보자 무엇. 인스턴스가 해제됩니다. 그런 다음 인스턴스에 액세스합니다.

결론은 OnTerminate 핸들러에서 스레드를 해제하지 않아야한다는 것입니다.

+0

이상한 ... 나는 "새로운 대답이 게시되었습니다 ..."라고 대답했습니다. 답변 버튼을 눌렀을 때 그대로였습니다. 그러나 답은 10 분 일찍 타임 스탬프로 나타났습니다. 너의 마법 능력은 절대 놀라지 않을거야, 데이빗! –

+0

하지만 그는 같은 스레드의 OnTerminate 핸들러에서 스레드를 해제하려고하지 않습니다. 내가 이해하기 때문에 그것은 2 개의 다른 스레드이며 그는 마스터 스레드의 OnTerminate 이벤트에서 슬레이브 스레드를 해제합니다. 내가 뭐 놓친 거 없니? –

+0

@ J ... 의심 스러울 때 원래 버전의 답변을 삭제했습니다. 'Free'에 대한 잘못된 호출로 인해 교착 상태가 발생하는지 궁금합니다. 분명히 틀렸지 만 나는 생각하지 않는다. 교착 상태가 발생했다고 생각합니다. –

관련 문제