我正在构建一个小型多线程web服务器。QTcpSockets是在主线程中获取的,然后由QtConcurrent交给QThreadPool,QThreadPool最终处理数据并发送一个答案。
我的问题是,套接字是在主线程中创建并在另一个线程中处理的。当试图写入套接字时,这会导致错误:
socket->write(somedata);
QObject:不能为处于不同线程中的父线程创建子线程。(父线程为QNativeSocketEngine(0x608330),父线程为QThread(0x600630),当前线程为QThread(0x505f60) )。
干净的方法是将套接字对象移动到处理线程,使用
socket->moveToThread(QThread::currentThread()).
但是,这只能在创建对象的线程中调用。此外,套接字将QTcpServer对象作为父对象,因此moveToThread()无论如何都会失败(父对象不能切换线程)。
如何将对象移动到线程池运行的代码中的QThread::currentThread()?或者,如何将其写入所创建线程外部的套接字?
发布于 2010-07-16 09:42:45
扩展QTcpServer
,重新实现incomingConnection(int socketDescriptor)
,并将套接字描述符传递给池中的线程。让QRunnable
从描述符创建QTcpSocket
并启动事件循环来接收套接字的信号。
发布于 2015-01-01 16:09:24
我也同意,捕获incomingConnection(int)
并在工作线程中创建套接字是这里的方法。
但是,您的问题是一个更基本的问题,因此请允许我展示一个解决一般问题的备选方案(将任意QObject
移动到线程池中的线程):
主线程中的
socket->moveToThread(nullptr);
这将挂起套接字的事件处理。然后将它传递给QtConcurrent.
socket->moveToThread(QThread::currentThread());
这将重新启动事件处理.
如果幸运的话,套接字将使它的套接字通知器再次在辅助线程的事件循环中重新注册,并且您可以从工作器提供连接。
不过,这里有两个重要的警告:
QThreadPool::globalInstance()
)上。正如函数的名称所示,线程池实例是一个全局资源,所有QtConcurrent用户都共享它,最好情况下阻塞它的工作线程会降低池的容量(因此,吞吐量),在最坏的情况下,您将使用工作线程的事件循环(由于第一点而不使用QTcpSocket
的同步API ),您需要调用QThread::currentThread()->exec()
来启动它。但是,这是一个阻塞调用,并且对线程池调度程序来说,工作人员看起来很忙,所以它不会交给它更多的任务(即。QRunnable
s).如果您实际上想要实现多线程tcp服务器,那么您就需要提交自己的线程池。
发布于 2010-06-26 23:04:03
布拉德利·胡格在Qt实验室上写了一篇关于这个话题的文章,也许这会对你有所帮助!
https://stackoverflow.com/questions/3126145
复制相似问题