代码之家  ›  专栏  ›  技术社区  ›  grefab

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

  •  7
  • grefab  · 技术社区  · 15 年前

    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.

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

    socket->write(somedata);
    

    QObject: Cannot create children for a parent that is in a different thread. (父母是 QNativeSocketEngine(0x608330), 父线程是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()).
    

    但是,只能在创建对象的线程内调用此函数。此外,套接字将qtcpserver对象作为父对象,因此movetothread()无论如何都将失败(父对象无法切换线程)。

    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?

    3 回复  |  直到 15 年前
        1
  •  4
  •   andref    15 年前

    延伸 QTcpServer 重新实施 incomingConnection(int socketDescriptor) and pass the socket descriptor to the threads in the pool. 有 QRunnable 创建 QTcpSocket from the descriptor and start an event loop to receive that socket's signals.

        2
  •  0
  •   fdermishin    13 年前

    布拉德利·胡格斯在Qt实验室写了一篇关于这个主题的文章,也许这会对你有所帮助!

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

        3
  •  0
  •   Marc Mutz - mmutz    11 年前

    我也同意 incomingConnection(int) 而在工作线程中创建套接字就是实现这一点的方法。

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

    1. 在主线程中:将套接字与任何线程分离:

      socket->moveToThread(nullptr);

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

    2. In the function executed on the thread pool, you 可以 现在打电话

      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.

    有两个 important caveats 这里,虽然:

    • 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.
    • 如果使用工作线程的事件循环(不使用 QTcpSocket , because of the first point), you'd need to call QThread::currentThread()->exec() 开始它。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)。

    如果您实际上想要实现一个多线程的TCP服务器,那么您将需要滚动您自己的线程池。