如何在使用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?