Management of QUdpSocket in multithreaded environment
-
I have problem with deleting QUdpSocket in my program. Problem is: I create UdpSocket in one thread, and then delete it in another. To simplify my code I have this:
@ class SocketHandler : public QObject
{
Q_OBJECT
public:
SocketHandler():
socket(this)
{
socket.bind(8888);
}
~SocketHandler();private: QUdpSocket socket; }; class ThreadStorage { public: ThreadStorage(): handler(new SocketHandler()), thread(new QThread()) { handler->moveToThread(thread); } ~ThreadStorage(); private: SocketHandler* handler; QThread* thread; }; class Killer : public QObject { Q_OBJECT public: Killer(ThreadStorage* stor): storage(stor) { } private: ThreadStorage* storage; public slots: void kill() { delete storage; }
};
And then I have slot connected to button in
MainWindow
:void MainWindow::onButton() { ThreadStorage* storage = new ThreadStorage(); QTimer* timer = new QTimer(); timer->setInterval(2000); timer->setSingleShot(true); Killer* killer = new Killer( storage); connect(timer, SIGNAL(timeout()), killer, SLOT(kill())); QThread* thread = new QThread(); connect(thread, SIGNAL(started()), timer, SLOT(start())); timer->moveToThread(thread); killer->moveToThread(thread); thread->start(); }@
When socket is deleted I have error:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 7287a0. Receiver '' (of type 'QNativeSocketEngine') was created in thread 709838", file kernel\qcoreapplication.cpp, line 521I'm using QT with msvc2013+opengl.
I understand memory leaks and other stupid errors in this particular code. This code is only for you to see what happens in my big program. It is just Minimal, Complete, and Verifiable example.
So, how do I properly manage UdpSocket in multithreaded app? Thanks. -
Use "QObject::deleteLater":http://qt-project.org/doc/qt-5/qobject.html#deleteLater
delete is executed in whatever thread it is called in. deleteLater schedules a deletion event that is delivered and handled in the owning thread of the target object. -
Yes, thank you, I figured this out, but in case someone is interested it's more than this. if you just do deleteLater, but you kill thread - deleteLater won't be called. Delete later is only called when both object and it's thread are alive. So, decision is
@
handler->deleteLater();
and also connect(handler, SIGNAL(destroyed), thread, SLOT(deleteLater));
@So handler->deleteLater() will be called with alive thread, but thread will be killed after destruction of handler.