2013-03-26 3 views
1

나는 정상적으로 그만 두라고 말하려고한다. 이를 위해 스레드는 모든 반복에서 전역 부울 플래그를 검사합니다.이 플래그는 스레드가 계속되거나 종료되어야하는지 여부를 나타냅니다. 내가 어떤 함수에서 true로 플래그를 설정하여 스레드를 중지하려고하면, 지금왜 내 스레드가 정상적으로 종료되지 않습니까?

ImageFusionQt::ImageFusionQt(QWidget* parent) 
: QMainWindow(parent) 
{  

captureThread = new QThread(); 
captureWorker = new CaptureWorker(); 

// Connects the threads started() signal to the process() slot in the worker, causing it to start. 
connect(captureThread, SIGNAL(started()), captureWorker, SLOT(process())); 

// Connect worker finished signal to trigger thread quit, then delete. 
connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit())); 
connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater())); 

// Make sure the thread object is deleted after execution has finished. 
connect(captureThread, SIGNAL(finished()), captureThread, SLOT(deleteLater())); 

// Give QThread ownership of Worker Object 
captureWorker->moveToThread(captureThread); 
captureThread->start(); 

} 

CaptureWorker.cpp

void CaptureWorker::process() 
{ 
    while(true) 
    { 
    g_exit_lock->lockForRead(); 
    if(g_exit) 
    { 
     g_exit_lock->unlock(); 
     break; 
    } 
    g_exit_lock->unlock(); 
    } 
    qDebug() << "CaptureWorker: Exiting."; 
    emit finished(); 
} 

: 스레드는 다음과 같이 설정 (코드 http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/에서이다)이다 process() 메서드는 반환하지만 스레드가 완료되지 않고 wait()에 대한 호출이 영원히 차단됩니다. 내 스레드가 종료되지 않는 이유는 무엇입니까?

g_exit_lock->lockForWrite(); 
g_exit = true; 
g_exit_lock->unlock(); 

QThread::sleep(15); 
qDebug() << "ct finished? " << captureThread->isFinished(); 

captureThread->wait(); 
qDebug() << "All threads stopped."; 

로그 파일 출력 :

2013.03.26 09:29:22[D] CaptureWorker: Exiting. 
2013.03.26 09:29:37[D] ct finished? false 

UPDATE

좀 디버깅을했고, 일부 intersting 물건을 발견 : 그 이벤트 루프에서

  • 스레드 블록 (QEventLoop를 :: exec). 그것은 분명히받지 못하는 quit() 신호를 기다립니다.
  • process()가 반환 된 후 스레드의 이벤트 루프가 생성됩니다. 입니다. 내가했던 것처럼 신호를 연결하면 스레드가 이미 작업을 마친 후에 (예 : process()가 반환 된 경우) 스레드의 run() 메서드가 호출됩니다.
  • 이벤트 루프는 실제 루프를 수행하기 전에 게시 된 모든 종료 이벤트를 지 웁니다.

내 결론

  • 내가 이벤트 루프가 종료() 멤버를 호출
  • 을 확정되는 시점에 이벤트가 삭제됩니다) (때문에 일을 그만 두지 않는 한 것처럼 종료() 슬롯에 연결 함수를 스레드 객체에 직접 적용하면 정상적으로 종료됩니다. 이것은 QThread :: currentThread() -> quit();을 사용하여 외부 또는 내부에서 수행 할 수 있습니다.

열기 질문

  • 이벤트 루프가 설립 된 후 과정() 메서드를 호출 할 수있는 방법이 있나요?
  • 작업이 모두 완료되면 이벤트 루프가 생성되는 것은 잘못되었습니다. 그러나 내가 QThread를 사용하는 방식은 다음과 같습니다. docs
+0

아마도 디버그 스트림을 플러시해야합니까? – Nick

+0

finished()의 내용은 무엇입니까? –

+0

로깅은 프로그램을 디버깅하는 데 매우 비생산적인 방법입니다. 대신 디버거를 사용하는 방법에 대해 알아보십시오. 디버거를 연결하고, 프로그램을 중단하고, 컨텍스트를 작업자 스레드로 전환하고 스택 추적에서 수행중인 작업을 찾으십시오. 높은 확률로 이제는 루프를 실행하지 않고 어떤 종류의 OS 호출에 묻혀서 캡처가 완료 될 때까지 기다릴 것입니다. 따라서 g_exit을 테스트하지 않으므로 종료하지 않습니다. –

답변

2

quit은 전혀 호출되지 않습니다. Qt가 직접 또는 대기중인 연결을 가지고 있다는 것을 알고 계십니다. 이것을 사용하면

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit())); 

입니다. 실제로 자동 연결 유형입니다. 따라서 captureWorker를 다른 스레드로 이동 했으므로 Qt::QueuedConnecton이 사용됩니다. quit()메인 스레드에서 호출됩니다.하지만 당신이하는 일은 메인 루프를 차단하는 것입니다. captureThread->wait();
quit()은 이벤트 루프에 대기하고 있지만 스레드가 끝나기를 기다리고 있기 때문에 차단됩니다. 당신이 편집에 제안처럼
그래서 직접)

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()), Qt::DirectConnection); 

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit())); 

를 대체하여 같은 직접) (종료 전화를 걸거나 (종료를 호출 할 수 있습니다, 또는 당신은 또한 같은 작업을 수행 할 수 있습니다 또는 당신의 완성() 신호를 스레드에 연결하고 어 할 수있는 당신이 정말로

QEventLoop l; 
    l.connect(captureThread, SIGNAL(finished()), SLOT(quit())); 
    l.exec(QEventLoop::ExcludeUserInputEvents); 

해야하는 경우 대신 captureThread->wait();의 다음 당신은 captureThread->wait(); 이후에하고 싶었으므로 수동으로 전혀 기다릴 필요가 없습니다.
Qt에서 여러 가지 방법이 있습니다

+0

입력 해 주셔서 감사합니다. Btw, 나는이 질문에 대답했다. 나는 당신의 대답을 이해하기 위해 고투하고있다 : 나는 captureThread가 주 스레드에 있다는 것을 알고 있지만, quit() 슬롯을 호출해도 그럼에도 불구하고 그것이 관리하는 스레드를 종료해야 하는가? 그리고 나는 당신의 제안이 단지 captureThread-> quit()보다 나은지 어떤 식 으로든 생각하지 않습니다. 그걸 확대 할 수 있니? 고마워. – binford

+0

예, quit()를 호출하면 이벤트 루프가 중지됩니다. 문제는 그것이 어디에 불려지는지입니다. captureThread는 주 스레드에 있기 때문에 Qt 클래스가 재진입 적이므로 주 스레드에서 메소드를 호출해야합니다. – spiritwolfform

+0

그런데 process()가 반환 된 후에 스레드의 이벤트 루프가 만들어 질 가능성이 있다고 생각하지 않습니다. 어쩌면 주 스레드의 이벤트 루프와 작업자 스레드 이벤트 루프를 섞어 놓은 것일 수도 있습니다. – spiritwolfform

0

문제는 실제로 스레드가 종료 신호를 수신하지 못하게하여 주 스레드와 이벤트 루프를 차단하고 있다는 것입니다. 다음과 같이하면 문제가 해결됩니다.

g_exit_lock->lockForWrite(); 
g_exit = true; 
g_exit_lock->unlock(); 

QThread::sleep(15); 
qDebug() << "ct finished? " << captureThread->isFinished(); 

// You are missing below line, without this, main thread will block 
captureThread->quit(); 
captureThread->wait(); 

qDebug() << "All threads stopped."; 
관련 문제