2010-06-27 64 views
7

我正在構建一個小型多線程Web服務器。在主線程中提取QTcpSockets,然後通過QtConcurrent交給QThreadPool,最終處理數據併發出答案。如何在使用QThreadPool時執行QObject :: moveToThread()?

我的問題是套接字在主線程中創建並在另一箇中處理。試圖寫入套接字時,這會導致錯誤:

socket->write(somedata); 

的QObject:無法創建一個 父母是在不同的線程的孩子。 (Parent是 QNativeSocketEngine(0x608330), 父母的線程的QThread(0x600630), 當前線程的QThread(0x505f60)

的清潔方法是使用

Socket對象移動到處理線程
socket->moveToThread(QThread::currentThread()). 

然而,這隻能在對象是在創建的線程中調用。此外,所述插座具有QTcpServer既可對象作爲母體,使moveToThread()將反正失敗(父對象不能切換線程)。

如何將對象移動到由線程池運行的代碼中的QThread :: currentThread()?或者,我如何寫入創建線程之外的套接字?

回答

4

擴展QTcpServer,重新實現incomingConnection(int socketDescriptor)和套接字描述符傳遞到池中的線程。使QRunnable從描述符中創建QTcpSocket並啓動一個事件循環來接收該套接字的信號。

0

Bradley Hugues在Qt實驗室寫了一篇關於這個主題的文章,也許這會對你有所幫助!

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

+0

謝謝,我知道這個職位。事實上,我現在正是以這種方式完成這項工作,但這不適用於我想要使用的線程池。當你將工作分配給多個線程時,最終你會編寫類​​似於花式池的東西,爲什麼不使用現有的呢? :) – grefab 2010-06-27 15:25:37

0

我也同意捕捉incomingConnection(int)並在工作線程中創建套接字是要走到這裏的方法。

但你的問題是更根本的一個,所以讓我表明,解決一般問題(移動任意QObject s到線程的線程池)的替代:

  1. 在主線程:從任何線程分離插座:

    socket-> moveToThread(nullptr);

    這將掛起事件處理的套接字。然後將其傳遞給QtConcurrent。

  2. 在線程池執行的功能,你可以現在調用

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

    這將重新啓動事件處理。

如果運氣好的話,套接字的套接字通知器會再次在工作線程的事件循環中重新註冊,並且您可以提供來自worker的連接。

有兩個重要的注意事項在這裏,雖然:

  • 你不應該把堵在全局線程池(QThreadPool::globalInstance())任務。正如函數的名稱所示,該線程池實例是一個全局資源,由QtConcurrent的所有用戶共享,並且在最佳情況下阻塞其工作線程會降低池的容量(因此吞吐量),最壞情況下會僵局。
  • 如果您使用工作線程的事件循環(由於第一點不使用同步API QTcpSocket),您需要撥打QThread::currentThread()->exec()來啓動它。然而,這是一個阻塞的調用,並且對於線程池計劃程序來說,工作人員看起來很忙,所以它不會把它交給更多的任務(即QRunnable s)。

如果你真的想實現一個多線程的tcp服務器,你將需要推出你自己的線程池。

相關問題