Solved QThread sanity check
-
I have an application that uses a QThread to handle in/outgoing socket data. It is using an event loop to receive signals and dispatch events, and I have not overridden anything on the QThread. I am simply creating a QThread, creating the worker object and moving it to the thread, then calling start() on the QThread. That all seems to be working fine.
The problem I was having was on shutdown. My app receives the aboutToQuitApp() signal, and want to send a final message over the socket via the following:
TapUserEventMessage* exit_message = new TapUserEventMessage(TapRequestAction::EXIT); emit outboundEngineData(exit_message); // terminate our communication thread, allowing the event queue to // flush engine_comm_handler.quit(); engine_comm_handler.wait();
The problem was that the receiver never got this final message. I assume its because the event loop simply stopped without dispatching the remaining messages.
So, I had the idea to emit a signal to the thread, telling it we are about to terminate and implemented the following in my worker object:
void CommunicationHandler::aboutToTerminate() { QThread::currentThread()->eventDispatcher()->processEvents( QEventLoop::AllEvents); QThread::currentThread()->exit(); }
I modified the handler for the aboutToQuitApp() signal as follows in my main app:
TapUserEventMessage* exit_message = new TapUserEventMessage(TapRequestAction::EXIT); emit outboundEngineData(exit_message); // terminate our communication thread, allowing the event queue to // flush emit aboutToTerminate(); engine_comm_handler.wait();
This seems to have solved the problem. The communications thread receives the signal, manually processes all remaining events and then tells the thread to exit, returning control back to the wait() command issued from my main app
What I am requesting is whether or not this was a good method of doing what I wanted
-
@DRoscoe
Actually, your first instinct was right:emit outboundEngineData(exit_message);
However make a slight modification. Make the signal that sends the engine data to be connected to the slot synchronously. Suppose you have
outboundExitMessage
signal. Just connect it like this:QObject::connect(controller, SIGNAL(outboundExitMessage(TapUserEventMessage *)), workerObject, SLOT(handlerOfMessage(TapUserEventMessage *)), Qt::BlockingQueuedConnection);
Then, you simply emit the signal:
emit outboundExitMessage(exit_message);
And the current thread will wait for the slot to finish execution before continuing on.
Kind regards.
-
@kshegunov Ah! yes, that's much cleaner. I would be concerned if there were many more events for the TapUserEventMessage, where I would not necessarily want to block, but in this case, there is not and it is a perfectly acceptable solution.
Thanks!
-
@DRoscoe
Well you can still have a non-blocking connection for one signal and a blocking one for another and both signals could be connected to the same slot, so I don't think this would be an issue.Kind regards.
-
@kshegunov Indeed. I mispoke. This approach does afford very fine granularity and it works like a charm!