3

我有来自生产者对象处理的某些硬件的实时数据流。这会连接到在自己的线程中处理它的消费者,以保持 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
}

我的问题是,在我销毁消费者对象之后 - 即使在断开连接之后,我仍然会收到信号。我已经尝试了一组越来越复杂的互斥锁来尝试阻止这种情况,但理想的解决方案是让清理等到所有未处理的信号都被处理完。

有没有办法监控有多少未处理的信号排队等待一个插槽?或者无论如何要清除它们?

4

3 回答 3

3

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

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

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

于 2012-08-01T21:38:28.467 回答
2

这里的问题是连接类型。您使用默认类型的连接,所以它是Qt::AutoConnection. 由于您正在连接来自不同线程的对象,因此它可以用作Qt::QueuedConnection.

现在我假设你的生产者创建数据比你的消费者吃它们更快。这导致消费者线程的事件队列中的数据缓冲。因此,当您断开信号时,您实际上已断开连接,但是您在事件队列中有大量数据在等待您,只给您一个仍然连接的填充。

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

祝你好运。

于 2012-08-01T22:13:29.237 回答
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调用,它应该在生产者而不是消费者上。

于 2012-08-01T19:53:27.667 回答