我有来自生产者对象处理的某些硬件的实时数据流。 这将连接到一个消费者,消费者在其自己的线程中处理它以保持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
}
我的问题是,在我销毁消费者对象之后 - 即使在断开连接后,我仍然会向其发送信号。我已经尝试了一组越来越复杂的互斥体试图阻止它,但理想的解决方案是让清理等到所有未完成的信号都被处理完毕。
无论如何都要监控有多少未处理的信号排队等待一个插槽?或者无论如何要清除它们?
答案 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
电话,它应该在制作人而不是消费者身上。