How to make QObject :: moveToThread () when using QThreadPool?

I am creating a small multi-threaded web server. QTcpSockets are retrieved in the main thread and then passed to QtConcurrent to QThreadPool, which ultimately processes the data and sends a response.

My problem is that the socket is created in the main thread and processed in another. This causes errors when trying to write to the socket:

socket->write(somedata); 

QObject: It is not possible to create children for a parent that is in another thread. (Parent of QNativeSocketEngine (0x608330), parent thread is QThread (0x600630), current thread is QThread (0x505f60)

A clean way would be to move the socket object into the processing flow using

 socket->moveToThread(QThread::currentThread()). 

However, this can only be called on the thread in which the object was created. In addition, the socket has the QTcpServer object as the parent, so moveToThread () will still fail (parent objects cannot switch threads).

How can I move an object to QThread :: currentThread () in the code that threadpool starts? Alternatively, how can I write to a socket outside the stream that was created?

+7
multithreading qt qt4
source share
3 answers

Extend QTcpServer , override incomingConnection(int socketDescriptor) and pass the socket handle to the threads in the pool. Create a QRunnable QTcpSocket from the handle and run an event loop to receive these socket signals.

+4
source share

Bradley Hug wrote a post in Qt Labs about this subject, maybe this will help you a little!

http://blog.qt.digia.com/2010/06/17/youre-doing-it-wrong/

0
source share

I also agree that the ingenuity of incomingConnection(int) and the creation of a socket in the workflow is the way to go here.

But your problem was more fundamental, so let me show you an alternative that solves a general problem (moving an arbitrary QObject to threads in a thread pool):

  • In the main thread: separate the socket from any thread:

    socket-> moveToThread (nullptr);

    This will pause the processing of the socket event. Then pass it to QtConcurrent.

  • In a function executed in a thread pool, you can call

    socket-> moveToThread (QThread :: currentThread ());

    This will restart event processing.

In any case, the socket will re-register its socket notifiers with the workflow event loop, and you will be able to service the connection to the worker.

There are two important caveats here :

  • You should not set blocking tasks in the global thread pool ( QThreadPool::globalInstance() ). As the name of the function shows, this instance of the thread pool is a global resource common to all QtConcurrent users and blocking its worker threads at best reduces the capacity (thus bandwidth) of the pool and in the worst case there will be a dead lock.
  • If you use a workflow event loop (not to use the synchronous QTcpSocket API, because of the first point), you need to call QThread::currentThread()->exec() to start it. However, it is a blocking call and a thread pool scheduler, the worker will look busy, so he will not transfer more tasks (i.e. QRunnable s).

If you really want to implement a multi-threaded tcp server, you will need to collapse your own thread pool.

0
source share

All Articles