Reputation: 4275
The title is very cryptic, so here goes!
I am writing a client that behaves in a very synchronous manner. Due to the design of the protocol and the server, everything has to happen sequentially (send request, wait for reply, service reply etc.), so I am using blocking sockets. Here is where Qt comes in.
In my application I have a GUI thread, a command processing thread and a scripting engine thread. I create the QTcpSocket in the command processing thread, as part of my Client class. The Client class has various methods that boil down to writing to the socket, reading back a specific number of bytes, and returning a result.
The problem comes when I try to directly call Client methods from the scripting engine thread. The Qt sockets randomly time out and when using a debug build of Qt, I get these warnings:
QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread
Anytime I call these methods from the command processing thread (where Client was created), I do not get these problems.
To simply phrase the situation:
Calling blocking functions of QAbstractSocket
, like waitForReadyRead()
, from a thread other than the one where the socket was created (dynamically allocated), causes random behaviour and debug asserts/warnings.
Anyone else experienced this? Ways around it?
Thanks in advance.
Upvotes: 4
Views: 4541
Reputation: 1553
I'm assuming that you're using QThread for the threading operations. If so, you can either a) use queued signal-slot connections; or b) explicitly use the QThread's event loop by creating a custom event type, posting that event in your scripting engine, and then having the client class handle those events.
example for a)
class ClientThread : public QThread
{
..stuff..
public slots:
waitForReadyRead();
};
class ScriptEngineThread : public QThread
{
..other stuff..
signals:
void requestWaitForReadyRead();
};
// In the ScriptEngineThread implementation...
ScriptEngineThread::setupClient()
{
connect(this, SIGNAL(requestWaitForReadyRead()),
client_, SLOT(waitForReadyRead()),
Qt::QueuedConnection);
}
Then, whenever you want to do the socket operations, just emit ScriptEngineThread::requestWaitForReadyRead();
. The major difficulty is, I assume, you need the scripting thread to wait for some socket operation to be done. In this case you'll need to fire signals back and forth between the threads, causing some circular dependancy.
For alternative b, it would require a little more coding work, but you could:
Upvotes: 4