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

我正在构建一个小型多线程Web服务器。 在主线程中提取QTcpSockets,然后通过QtConcurrent交给QThreadPool,最终处理数据并发出答案。

我的问题是套接字在主线程中创建并在另一个中处理。 尝试写入套接字时会导致错误:

socket->write(somedata);

QObject:无法为处于不同线程中的父项创建子项。 (Parent是QNativeSocketEngine(0x608330),父线程是QThread(0x600630),当前线程是QThread(0x505f60)

干净的方式是使用套接字对象移动到处理线程

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

但是,这只能在创建对象的线程中调用。此外,套接字将QTcpServer对象作为父对象,所以moveToThread()将无法继续(父对象无法切换线程)。

如何将对象移动到由线程池运行的代码中的QThread :: currentThread()? 或者,我如何写入创建线程之外的套接字?


扩展QTcpServer ,重新实现incomingConnection(int socketDescriptor)并将套接字描述符传递给池中的线程。 让QRunnable从描述符创建QTcpSocket并启动一个事件循环来接收该套接字的信号。


Bradley Hugues在Qt实验室写了一篇关于这个主题的文章,也许这会对你有所帮助!

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


我也会同意捕获incomingConnection(int)并在工作线程中创建套接字是这里的方法。

但是你的问题是一个更基本的问题,所以让我展示一个解决一般问题的替代方案(将任意QObject移动到线程池中的线程):

  • 在主线程中:从任何线程分离套接字:

    插座 - > moveToThread(nullptr);

    这将挂起套接字的事件处理。 然后将其传递给QtConcurrent。

  • 在线程池上执行的函数中,您现在可以调用

    插座 - > moveToThread(的QThread :: currentThread());

    这将重新启动事件处理。

  • 如果运气好的话,套接字的套接字通知器会再次在工作线程的事件循环中重新注册,并且您可以提供来自worker的连接。

    但是,这里有两个重要的警告

  • 您不应该在全局线程池( QThreadPool::globalInstance() )上放置阻塞任务。 正如函数的名称所示,该线程池实例是一个全局资源,由QtConcurrent的所有用户共享,并且在最佳情况下阻塞其工作线程会降低池的容量(因此吞吐量),最坏情况下会僵局。
  • 如果你使用工作线程的事件循环(因为第一点不使用QTcpSocket的同步API),你需要调用QThread::currentThread()->exec()来启动它。 然而,这是一个阻塞的调用,并且对于线程池调度器来说,工作人员看起来很忙,所以它不会把更多的任务交给它(即QRunnable s)。
  • 如果你实际上想要实现一个多线程的tcp服务器,你将需要推出你自己的线程池。

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

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

    下一篇: SIMD/SSE newbie: simple image filtering