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?
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.