2011-06-13 2 views
2

테스트 중에 C++ Builder/Delphi 응용 프로그램이 백그라운드 작업자 스레드에서 캐치되지 않는 예외를 발생 시켰습니다. EurekaLog은 예상대로 예외를 포착하고 오류 보고서를 보냈고 모든 것이 정상적으로 보였습니다.C++ Builder/Delphi 스레드 및 응용 프로그램이 종료되지 않는 원인은 무엇입니까?

그러나 응용 프로그램의 주 창을 닫을 때 응용 프로그램이 여전히 작업 관리자에 나열되어 있었고 (여전히 자원이 열려 있었기 때문에) 백그라운드에서 실행중인 상태로 남아있었습니다.

의도적으로 배경 작업자 스레드에 다양한 버그를 도입하여이 문제를 재현하려고했지만 시도 할 수 없습니다.

주 창을 닫은 후에도 스레드와 응용 프로그램이 계속 실행될 수 있습니다 (아마도 PostQuitMessage가 호출되었을 수도 있습니다)?

응용 프로그램이 항상 완전하게 종료되도록하려면 어떻게해야합니까?

+0

끊임없이 차단할 수있는 EnterCriticalSection 코드가 있습니까? 그것은 종료시에 바로 얻을 수있는 매우 일반적인 교착 상태입니다. –

답변

7

첫 번째 규칙은 스레드의 주 실행자 메소드가 신호를 보내고 올바르게 종료되도록 작성해야한다는 것과 두 번째 규칙은 앱의 메인 스레드를 먼저 종료하지 말아야한다는 것입니다. 자신의 시간에 다른 스레드가 종료되면 안전을 위해 모든 백그라운드 스레드가 중지되도록 신호를 보내고 종료가 완료 될 때까지 기다린 다음 주 스레드를 종료해야합니다. 최소한의 THREAD 예 :

procedure TMyThread.Execute; 
begin 
    Init; 
    while not Terminated do 
     OneWorkItem; // inside OneWorkItem, you ALSO need to check for Terminated 
end; 

최소한의 기본 폼/메인 스레드 예 : 당신은 FPendingShutdownFlag을 설정하고 응용 프로그램 유휴 처리 루프에서 호출 위의 기능을 가질 수

procedure TMyMainForm.CheckAndShutdown; 
    begin 
    if FPendingShutdownFlag then 
     if AllBackgroundThreadsTerminated then 
      Self.Close; 
    end; 

. 사용자가 FormClose 기본 폼을 클릭 할 때 AllBackgroundThreadsTerminated가 false를 반환하면 CanClose를 false로 설정하고 FPendingShutdownFlag := true을 대신 설정하십시오.

무한 루프를 만들면 (사실이라면) 응용 프로그램이 정상적으로 종료되지 않습니다. 어떻게 든 응용 프로그램이 종료되고 실행중인 스레드가 갑자기 꺼지거나 교착 상태에 빠지거나 그렇지 않으면 실패 할 수 있습니다. 스레드 1의 리소스를 사용 중일 수 있으므로 스레드 1에서 해제 중입니다.

인터럽트 가능하도록 쓰레드 실행 메소드를 작성하지 않았거나, 메인 쓰레드와 VCL 및 그 객체의 종료를 시작할 수 있기 때문에 백그라운드 스레드가 다음과 같다면 의도 한 경쟁 조건이 하나 이상있을 수 있습니다. 완전히 닥쳐.

+0

나 자신을 충분히 설명하면 안된다. 인터럽트가 가능하도록 쓰레드를 작성하고 TThread.Terminated를 확인하기 위해 최선을 다해 교착 상태 및 리소스 문제 등을 피할 수있었습니다. 어쨌든 한 번, 내 애플리케이션이 종료되지 않았습니다. 양식이 닫혀 있더라도 백그라운드에서 계속 실행되었습니다. 나는 그것을 왜 방지해야 하는지를 알고 싶습니다. 오류 상태 (중복없는 while (true) 루프 추가 포함)를 복제하기 위해 생각할 수있는 모든 작업을 수행 했으므로 복구 방법을 파악할 수 있지만 오류 상태를 복제 할 수는 없습니다. –

+0

그런 다음 코드에서 애매한 경쟁 조건 또는 기타 유사한 간헐적 인 비동기 오류를 검색하는 것처럼 들립니다. 오랫동안 블로킹하고있는 TThread.Synchronize 호출이 있습니까? 수면() 전화가 있으십니까? 당신은 내가 "잠자는 아름다움"문제라고 부를 수도 있습니다. 백그라운드 스레드가 ANY 오브젝트를 전혀 사용하지 않거나 주 스레드가 해제 될 것이라고 표명 할 경우 주 스레드를 종료하기 전에 백그라운드 스레드를 완전히 종료해야합니다. –

+0

많은 디버깅 메시지를 사용하여 코드를 작성한 다음 MS DebugView (출력 디버거 뷰어)와 함께 코드가 실패한 클라이언트 시스템에서 코드를 실행하고 코드의 어떤 부분을 확인해야합니다. 클라이언트 시스템에 도달했거나 도달하지 못했습니다. –

1

작업자 스레드가 종료되었으며 주 스레드가 완료 될 때까지 기다리지 않았습니까?

+0

나는 무슨 일이 일어 났는지 잘 모르겠다. 나는이 문제를 한 번 보았지만 고객의 컴퓨터에서 재발하지 않도록하고 싶다. 고의적으로 작업자 스레드를 종료하지 않게하려면 (C++에서 "while (true);"루프를 추가하여) 응용 프로그램을 여전히 종료합니다. 따라서 주 스레드가 종료 할 작업자. –

+0

잠깐. 스레드가 종료되지 않도록 while 루프를 추가했습니다. 하지만 다른 곳에서는 TThread.Terminate를 호출 할 수 있습니다. 그래서 당신이 한 일은 그것이 아주 쉬게 될 가능성이 거의 없도록 만드는 것입니다. 귀하의 앱이 고장난 것도 당연합니다. –

+0

@ 워렌 P : 나는 당신이 오해했을 수도 있다고 생각합니다. 당신의 대답에 대한 제 코멘트를보십시오. –