插槽断开后的Qt信号

时间:2012-08-01 19:40:19

标签: qt signals-slots qthread

我有来自生产者对象处理的某些硬件的实时数据流。 这将连接到一个消费者,消费者在其自己的线程中处理它以保持gui的响应。

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 个答案:

答案 0 :(得分:3)

您似乎正在从与其所在的线程不同的线程中销毁消费者对象.QObject通常会在销毁时处理所有断开连接和事件队列清除,如果要在正确的线程中完成。来自Qt's documentation

  

从拥有该对象的线程以外的线程调用QObject上的删除(或以其他方式访问该对象)是不安全的,除非您保证该对象当时没有处理事件。改为使用QObject :: deleteLater(),并发布一个DeferredDelete事件,该事件的线程的事件循环将最终被接收。

只需将清理放在使用者的析构函数中,然后使用QMetaObject::invokeMethod(consumer, "deleteLater");让消费者从其自己的线程中销毁自己。在插槽上使用invokeMethod将以线程安全的方式将调用发送到deleteLater,这似乎是必要的,因为我看不到任何文档说deleteLater本身就是线程安全的。如果必须阻止消费者销毁,您可以将连接类型指定为Qt::BlockingQueuedConnection,否则默认值Qt::AutoConnection应该没问题。

答案 1 :(得分:2)

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

现在我假设您的生产者创建数据的速度要快于消费者吃掉它们。这导致在消费者线程的事件队列中缓冲数据。因此,当您断开信号时,您实际上已断开连接,但在事件队列中有大量数据等待您,只为您提供仍然连接的填充。

如何解决?使消费者更快或在消费者中添加一些标志,这将导致忽略数据进入消费者插槽。或者让生产者变慢。尝试不同的沟通模式。或者使用concurrent API将作业拆分为多个线程。 最佳解决方案取决于您正在做什么的细节。

祝你好运。

答案 2 :(得分: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电话,它应该在制作人而不是消费者身上。