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

I'm building a small multithreaded web server. The QTcpSockets are fetched in the main thread and then hand over by QtConcurrent to the QThreadPool, which eventually processes the data and sends out an answer.

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

socket->write(somedata);

QObject: Cannot create children for a parent that is in a different thread. (Parent is QNativeSocketEngine(0x608330), parent's thread is QThread(0x600630), current thread is QThread(0x505f60)

The clean way would be to move the socket object to the processing thread using

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

This, however, can only be called within the thread the object was created in. Furthermore, the socket has the QTcpServer object as parent, so moveToThread() will fail anyway (parented objects cannot switch threads).

How can I move the object to the QThread::currentThread() within the code that is run by the threadpool? Alternatively, how can I write to a socket outside the thread it was created?


Extend QTcpServer , reimplement incomingConnection(int socketDescriptor) and pass the socket descriptor to the threads in the pool. Have the QRunnable create the QTcpSocket from the descriptor and start an event loop to receive that socket's signals.


Bradley Hugues wrote a post on the Qt Labs talking about this subject, maybe this will help you a bit !

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


I would also agree that catching incomingConnection(int) and creating the socket in the worker thread is the way to go here.

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

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

    socket->moveToThread(nullptr);

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

  • In the function executed on the thread pool, you can now call

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

    This will re-start event processing.

  • With any luck, the socket will have its socket notifiers re-registered with the worker thread's event loop again, and you can serve the connection from the worker.

    There are two important caveats here, though:

  • You should not put blocking tasks on the global thread pool ( QThreadPool::globalInstance() ). As the name of the function suggests, that thread pool instance is a global resource, shared by all users of QtConcurrent, and blocking its worker threads in the best case reduces the capacity (thus, throughput) of the pool and in the worst case will dead-lock.
  • If you use the event loop of worker threads (to not use the synchronous API of QTcpSocket , because of the first point), you'd need to call QThread::currentThread()->exec() to start it. That, however, is a blocking call and to the thread pool scheduler, the worker will look busy, so it will not hand it more tasks (ie. QRunnable s).
  • If you actually want to implement a multi-threaded tcp server, you'll therefore need to roll your own thread pool.

    链接地址: http://www.djcxy.com/p/46628.html

    上一篇: 在Django admin中有条件内联?

    下一篇: 如何在使用QThreadPool时执行QObject :: moveToThread()?