1. 程式人生 > >Qt中採用多執行緒實現Socket程式設計

Qt中採用多執行緒實現Socket程式設計


      本文介紹的是Qt中採用多執行緒Socket程式設計,由於工作專案的需要,使用Qtsocket程式設計。Qt裡的example是個不錯的教程,但是當我把程式碼移植到多執行緒的環境時就出問題了:
QObject: Cannot create children for a parent that is in a different thread.

由於想要線上程中保留一個socket,以便維持雙邊通訊,因此定義如下:

SocketThread:public QThread

{

....

private:

QTcpSocket _tcpSocket;

}

但是這段程式碼並無法正常的完成工作,後來在網上搜了一下資料,找到以下解釋(忘了出處了,以下是中文的大概意思):“ 在QThread中定義的所有東西都屬於建立該QThread的執行緒。“

問題出來了,如果按照這個定義,在SocketThread中定義的_tcpSocket,其實是屬於mainThread(SocketThread是在main函式中建立),而當我們在SocketThread中的run函式使用到_tcpSocket的時候,其實是跨執行緒呼叫,這樣就會出現上面的異常。

解決方法: 需要對SocketThread的定義做一下更改:
SocketThread:public QThread  

 ....  
 private:  
 QTcpSocket* _tcpSocket;  
 }  

在上面我們並沒有建立具體的物件,而是定義了一個指標,而如何讓指標內的內容從屬於SocketThread這個執行緒呢?答案就是要在SocketThread的run方法中初始化  
SocketThread::run()

 ... ;  
 _tcpSocket
= new QTcpSocket();

進行以上修改之後上面的異常就不再出現了。

      但如果在run()函式中,建立_tcpSocket後,進行相應的訊號與槽連線,如
    connnect(_tcpSocket, SIGNAL(readyRead), this, SLOT(slot_read());
    this->exec();
    最後進入事件迴圈;這時,此套接字有可讀的訊息,則同樣的會發生跟上面類似的錯誤:
QObject: Cannot create children for a parent that is in a different thread.

(Parent is QNativeSocketEngine(0x1f5f9e8), parent's thread is MyThread(0x1f972c8), current thread is QThread(0x717868)
    為解決這個問題,修改連線函式如下:
  connnect(_tcpSocket, SIGNAL(readyRead), this, SLOT(slot_read(), Qt::DirectConnection);
    具體解釋,詳見手冊,
Qt::AutoConnection  (default) Same as DirectConnection, if the emitter and receiver are in the same thread. Same as QueuedConnection, if the emitter and receiver are in different threads.

Qt::QueuedConnection  The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.