Reputation: 96167
I have a stream of real time data from some HW handled by a producer object. This gets connected to a consumer that process it in it's own thread to keep the gui responsive.
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
}
My problem is that after I destroy the consumer object - I still get signals posted to it, even after doing a disconnect. I've tried an increasingly complex set of mutexes to try and stop this but the ideal solution would be for the cleanup to wait until all outstanding signals are processed.
Is there anyway to monitor how many unhandled signals are queued for a slot? Or anyway to clear them?
Upvotes: 3
Views: 4819
Reputation: 38161
Problem here is type of connection. You use default type of connection so it is Qt::AutoConnection
. Since you are connecting objects from different threads this works as Qt::QueuedConnection
.
Now I assume that your producer creates data faster then your consumer eats them. This leads to buffering of data in event queue of the consumer thread. So when you disconnect signal you are really disconnected but you have bunch of data waiting for you in event queue giving you only a filling that you are still connected.
How to fix it? Make consumer faster or add some flag in consumer which will cause ignore data coming to consumer slot. Or make producer slower. Try different pattern of communication. Or use concurrent API which will split job to multiple threads. Best solution depends on details what are you doing.
Good luck.
Upvotes: 3
Reputation: 4424
You seem to be destroying the consumer object from a different thread than the one that it lives in. QObject would normally handle all disconnection and event queue clearing itself upon destruction, were it to be done in the correct thread. From Qt's documentation:
Calling delete on a QObject from a thread other than the one that owns the object (or accessing the object in other ways) is unsafe, unless you guarantee that the object isn't processing events at that moment. Use QObject::deleteLater() instead, and a DeferredDelete event will be posted, which the event loop of the object's thread will eventually pick up.
Just put the cleanup in the destructor of the consumer, and use QMetaObject::invokeMethod(consumer, "deleteLater");
to get the consumer to destroy itself from inside its own thread. Using invokeMethod on the slot will send the call to deleteLater in thread-safe manner, which seems to be necessary as I see no documentation that says deleteLater is thread-safe itself. If you must block until the consumer is destroyed, you can specify the connection type to be Qt::BlockingQueuedConnection
, but otherwise the default of Qt::AutoConnection
should be fine.
Upvotes: 3
Reputation: 2829
Ensure that you aren't connecting signals multiple times otherwise taking a look at this mailing list archive could give you some hints/suggestions:
http://lists.trolltech.com/qt-interest/2000-05/thread00051-0.html
In short maybe try:
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 );
}
Edit: Fixed the blockSignals
call, it should be on the producer not the consumer.
Upvotes: 1