I am moving some sockets from main thread to worker thread and processing readyRead(), close(), write() etc. on the new thread. Rarely I see below dangerous warning:
"QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread"
Usually the execution after this warning results in undefined behaviour (crash / uncaught exception / normal).
Have checked all the signal/slot to the socket and they seem proper. From my experience, usually the above warning will be frequent or quick if there is any coding irregularity.
Now I am suspecting if moveToThread() does its job as expected or not! Because from QEvent documentation a QEvent::ThreadChange is raised as the last event on the current thread during this function call.
The object is moved to another thread. This is the last event sent to this object in the previous thread. See
QObject::moveToThread()1.
1 AQEvent::ThreadChangeevent is sent to this object just before the thread affinity is changed. You can handle this event to perform any special processing.
In my code, I am not checking for this event. Rather I assume that, once the moveToThread() is finished, the thread affinity is changed and the new "signal/slot" on the object is guaranteed on the new thread.
Question:
- Is it safe to move the sockets to another thread?
- Will
moveToThread()assure that the signals on that object are also moved to the new thread just after this function? - How should it be designed to assure no threading irregularity with Sockets?
BTW, in the latest Qt debugger it lands on following code segment:
// qsocketnotifier.cpp
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
return;
}
Below is the stack frame for the main thread:

Below is the stack frame for the worker thread, which halts on the logging:

Qt sockets are NOT supported with
moveToThread()idiom!!!I wish Qt had documented this fact as LOUD as above. I have spent weeks of debugging an issue which is not meant for fixing. Socket
moveToThread()issue is so complicated, that it doesn't happen consistently. I could reproduce it consistently only after testing a customisedQTcpServersubclass with lots of socket open/close scenario.Later I came across this post: How do I execute QTcpSocket in a different thread?. This answer explicitly states that sockets are not supported for the movement across the threads.
Here are the documentations from
QTcpServerProbably this will apply to the
QWebSocketServertoo!So the best approach is to overload
incomingConnection()and call its internal in another thread.If done so, the
addPendingConnection()andnextPendingConnection()idiom may not be required, even though it's mentioned in a note.QWebSocketServeris stricter thanQTcpServerThis is another fact, which wasted more time for me. In
QTcpServer, we can overload theincomingConnection()and pass on the socket descriptor to another thread to create a socket. However,QWebSocketServerdoesn't have such overload. Mostly because,QSslSocketreceived inQTcpServergets upgraded toQWebSocketand passed on to theQWebSocketServervia itshandleConnection()method.So
QWebSocketmust be created whereQWebSocketServerresides!. Hence in whichever threads, we want aQWebSocketto be created, all those threads need to have an object ofQWebSocketServer. Idiomatically we can have oneQTcpServerlistening on a single port and can keep passing itsQTcpSockets (upgraded toQWebSockets) to these various threads'QWebSocketServers in a load balancing way.A message to Qt developers
I wish that, you can save lot of time of the developers relying on the Qt library by a simple compilation error. This will negate all the wrong articles floating around internet which suggest how to use
moveToThread()on aQTcpSocket. Just introduce below method:Update: Raised QTBUG-82373.