2012-08-01 90 views
3

我有一个由生产者对象处理的一些硬件的实时数据流。 这会连接到一个消费者,它在它自己的线程中处理它,以保持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() – 2012-08-02 14:52:37

+0

我不太明白你的意思。消费者线程是否在QAbstractSocket :: waitFor *上被阻塞? – cgmb 2012-08-02 19:56:05

+0

我得到了一个有关deleteLater和QTimer的警告,他是否连接了socket,我认为它必须是TCP套接字,因为线程中没有使用明确的定时器。 – 2012-08-02 21:07:36

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

谢谢,但似乎并没有阻止管道中的信号。 – 2012-08-01 20:41:22

2

这里的问题是type of connection。您使用default type of connection,因此它是Qt::AutoConnection。由于您正在连接来自不同线程的对象,因此它的工作方式为Qt::QueuedConnection

现在我假设你的制作者更快地创建数据,然后你的消费者吃掉它们。这导致消费者线程的事件队列中的数据缓冲。所以,当你断开信号,你真的断开连接,但你有一堆数据等待你在事件队列中给你只填充,你仍然连接。

如何解决?让消费者更快或者在消费者身上添加一些标志,这会导致忽略消费者插槽中的数据。或者让制片人变慢。尝试不同的沟通模式。或使用concurrent API将作业分成多个线程。 最好的解决方案取决于细节你在做什么。

祝你好运。