2012-08-01 3 views
3

생산자 개체가 처리하는 일부 HW의 실시간 데이터 스트림이 있습니다. 이것은 gui를 계속 응답하기 위해 자체 스레드에서 처리하는 소비자와 연결됩니다.슬롯 연결 해제 후 Qt 신호

mainwindow::startProcessing(){ 
    QObject::connect(producer,SIGNAL(dataReady(data*),consumer,SLOT(doData(data*))); 
    consumer->moveToThread(&consumerThread);   
    consumerThread.start(); 
} 

mainwindow::stopProcessing(){ 
    producer->disconnect(SIGNAL(dataReady(data*)); 
    consumer->cleanup();       
    delete consumer; 
} 

consumer::doData(data* x) { 
    mutex.lock(); 
    processingObject stuff 
    mutex.unlock() 
} 

consumer::cleanup() { 
    mutex.tryLock(); 
     .... blah .... 
     delete processingObject; // then doData gets called again 
} 

소비자 개체를 삭제 한 후에도 문제가 발생합니다. 연결을 끊은 후에도 여전히 신호가 게시됩니다. 점점 더 복잡한 뮤텍스를 시도해 보았습니다. 그러나 이상적인 해결책은 대기중인 신호가 모두 처리 될 때까지 기다리는 것입니다.

슬롯에 대기중인 처리되지 않은 신호의 수를 모니터하는 방법이 있습니까? 아니면 어쨌든 그들을 취소 하시겠습니까?

답변

3

소비자 개체가 살고있는 스레드와 다른 스레드에서 파손 된 것처럼 보입니다. QObject는 정상적으로 모든 연결 끊기 및 이벤트 큐를 파기 할 때 자체적으로 처리합니다. 올바른 스레드에서 수행했는지 확인합니다. Qt's documentation에서 : 당신이 객체가에서 이벤트를 처리하고 있는지 보장하지 않는

하여 객체를 소유 한 (또는 다른 방법으로 개체를 액세스)가 아닌 다른 스레드에서 QObject를에 삭제 호출, 안전하지 않은 순간. 대신 QObject :: deleteLater()를 사용하면 DeferredDelete 이벤트가 게시되어 객체 스레드의 이벤트 루프가 결국 선택됩니다.

소비자의 소멸자에 정리를 넣고 QMetaObject::invokeMethod(consumer, "deleteLater");을 사용하여 소비자가 자체 스레드에서 자신을 파괴하도록하십시오. 슬롯에서 invokeMethod를 사용하면 스레드 안전 모드에서 deleteLater에 대한 호출이 전송됩니다. 이는 deleteLater가 스레드 안전 그 자체라는 문서가 없기 때문에 필요합니다. 소비자가 파열 될 때까지 차단해야하는 경우 연결 유형을 Qt::BlockingQueuedConnection으로 지정할 수 있습니다. 그렇지 않은 경우 기본값은 Qt::AutoConnection이어야합니다.

+0

Unfortunatley 처리에는 타이머가있는 TCPSocket이 관련되어 있으며 타이머에서 대기중인 스레드에서 deleteLater()를 사용할 수 없습니다. –

+0

나는 사용자의 뜻을 이해하지 못합니다. 소비자 스레드가 QAbstractSocket :: waitFor *에서 차단 되었습니까? – cgmb

+0

deleteLater와 QTimer에 대한 경고를 받았는데, 스레드가 명시적인 타이머를 사용하고 있지 않기 때문에 소켓이 연결되어 있어야합니다. –

1

당신이 그렇지 않으면 당신에게 몇 가지 힌트/제안 줄 수있는이 메일 링리스트 아카이브를 살펴 복용 신호를 여러 번 연결하지되어 있는지 확인 어쩌면 시도 요컨대

http://lists.trolltech.com/qt-interest/2000-05/thread00051-0.html

을 :

mainwindow::stopProcessing() 
{ 
    // Block the producer's signals. 
    producer->blockSignals(true); 

    // Perform clean up/stop 
    consumer->cleanup(); 

    // Delete the consumer, this disconnects all signals connected 
    // to the consumer. 
    delete consumer; 

    // Restore the producer's signals 
    producer->blockSignals(false); 
} 

편집 : blockSignals 호출이 수정되었으므로 소비자가 아닌 생산자가 있어야합니다.

+0

감사하지만 파이프에있는 신호를 차단하지는 않습니다. –

2

문제는 여기 type of connection입니다. default type of connection을 사용하므로 Qt::AutoConnection입니다. 다른 스레드의 객체를 연결하기 때문에 Qt::QueuedConnection으로 작동합니다.

이제 제작자가 데이터를 더 빨리 생성 한 다음 사용자가 먹는다고 가정합니다. 이로 인해 소비자 스레드의 이벤트 큐에 데이터가 버퍼링됩니다. 따라서 신호를 연결 해제하면 실제로 연결이 끊어져도 이벤트 대기열에서 기다리는 데이터가 많아서 연결되어있는 채우기 만 제공됩니다.

문제를 해결하는 방법은 무엇입니까? 소비자를 더 빠르게 만들거나 소비자에게 플래그를 추가하여 소비자가 데이터를 무시하게 만듭니다. 또는 제작자의 속도를 늦추십시오. 다른 의사 소통 패턴을 시도하십시오. 또는 작업을 여러 스레드로 분할하는 concurrent API을 사용하십시오. 최상의 솔루션은 세부 사항에 달려 있습니다.

행운을 비네.