Qt socket locking functions needed to run in QThread, where they are created. Somehow past this?

The name is very mysterious, so here it is!

I write a client who behaves very synchronously. Due to the design of the protocol and the server, everything should happen sequentially (send a request, wait for a response, a response from a service, etc.), so I use blocking sockets. Here is the Qt.

In my application, I have a GUI thread, a command processing thread, and a script engine thread. I am creating a QTcpSocket in a command flow as part of my Client class. The Client class has various methods that boil down to writing to a socket, reading a certain number of bytes and returning a result.

The problem occurs when I try to directly call Client methods from the script engine thread. Qt sockets randomly fail and when using the Qt debug build I get the following warnings:

QSocketNotifier: socket notifiers cannot be enabled from another thread QSocketNotifier: socket notifiers cannot be disabled from another thread 

At any time, when I call these methods from the command flow (when the client was created), I do not get these problems.

To just tell the situation:

Calling QAbstractSocket locking functions, such as waitForReadyRead() , from a thread other than where the socket was created (dynamically allocated), causes random behavior and debugging of statements / warnings.

Has anyone else experienced this? Ways around him?

Thanks in advance.

+4
source share
1 answer

I assume that you are using QThread for streaming operations. If so, you can: a) use queues of signal connectors ; or b) explicitly use the QThread event loop by creating a custom event type, placing this event in your script engine, and then, using the client class, process these 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, when you want to perform socket operations, just emit ScriptEngineThread::requestWaitForReadyRead(); . The main problem is that, in my opinion, you need a stream of scripts to wait for any socket operation to complete. In this case, you will need to send signals between threads, causing some cyclic dependence.

Alternative b will require a bit more coding work, but you can:

  • Create your own QEvent subclasses
  • Create a class to mediate, host and process each of your QEvents, and emit signals to communicate with streams - each stream can have an instance of this
  • Connect the client and script engine to the signal of the event it cares about.
+4
source

Source: https://habr.com/ru/post/1342054/


All Articles