1. 程式人生 > >qt GUI執行緒和其他執行緒的訊號槽以及不同執行緒通訊

qt GUI執行緒和其他執行緒的訊號槽以及不同執行緒通訊

Qt所有的對於GUI的操作只能在一個GUI執行緒中執行,也就是return QApp::exec的執行緒。

一般main裡面這樣寫。那麼所有的GUI的操作只能在main主執行緒中執行。

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

WidgetUi w;
w.show();

return a.exec();
}

執行a.exec()程式進入訊息迴圈。開始處理訊息

如果打算CreateThread,把ui的指標傳過去 在thread裡面操作UI。是不行的

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

WidgetUi w;
w.show();

       CreateThread(thread_proc,&w);

return a.exec();
}

thread_proc(void* arg)

{

      ui=(WidgetUi *)arg;

     ui->textedit.settext(xxx);

}

在thread_proc中的ui的確是有效的指標。但是這麼操作ui。容易崩潰並且不一定達到想要的效果。

1可能崩潰的原因是 沒有加鎖同步操作某個資料。比如主GUI執行緒正在讀取一個list。此時另一個非gui執行緒刪除了同一個list當中的某項。就崩潰了。

所有GUI操作只在一個執行緒內進行。這樣就不用加考慮鎖,思路簡單清晰。一旦加鎖。各種難以理解的問題就來了。

老師在批改作業。數了一下一共20本。老師說小明你的作業有問題,先拿下去修改。小明拿走一本了作業。

老師知道還剩19本。這是同一執行緒操作

如果小明自己回憶作業有問題,沒告訴老師。而是直接拿走了。老師數來數去少了一本,老師就迷糊了。

2達不到預期的效果。

比如非gui執行緒用settext設定了 text。但是介面上可能不會顯示。

因為你的執行緒修改了text的內容,但是沒有通知GUI執行緒,所以GUI執行緒不會畫出來,直到他下次處理某些事件的時候才會一併重新整理。

老師還在改作業,別的同學告訴老師作業做好了。老師說你放到。我一個個改。通知一個就改一個。小明沒告訴老師,

而是直接把作業放到那一堆本子裡。老師不知道,所以沒改。直到另一個同學說交作業了。老師才批改。才發現小明的也在這裡。然後才一起批改了

其他執行緒和GUI執行緒通訊。

如果想在createThread的執行緒裡面通知UI進行操作怎麼辦。通過訊號和槽實現。

如果要用訊號和槽。那麼必須繼承QObject 必須在類裡面

所以可以定義一個訊號發射類。

class Msg:public QObject

   Q_OBJECT

 public:

  void sendsig(int arg)

  {

      emit sig(arg);

  };

signals:

 void sig(int arg);

}

connect(sig(),someslot());

Qt5以後signals變成public了。可以直接呼叫emit

Qt4是protected。不能直接呼叫。要寫個public函式呼叫。

在外部定義一個 Msg  msgsender

這樣在 thread_proc裡面

{

     msgsender.sendsig(arg);

}

這樣是可以的。

特別注意。這樣的訊號發射類一般只能做發射。不能接受訊號。

因為如果要能傳送和接受的都可以。這個QObject必須存在於一個生存的執行緒中。並且這個執行緒擁有事件迴圈。

也就是qt說的執行緒親和性

如果QObject的-thread返回0或者生存在一個沒有事件迴圈的執行緒當中。那麼這個Qobject無法接受佇列訊號。和post過來的event

這個理解起來很簡單。如果沒有事件迴圈機制。執行緒去哪裡取得投遞到他佇列裡面的訊息呢?

例如

thread_proc

{

      p=new QObject

      while(1)

     {

   sleep(100);       

     }

}

只要外部投遞的是佇列形式的訊號。p的相關聯的槽都不會被執行。因為執行緒一直在死迴圈。根本沒機會從佇列中取訊息

但是通過指定DirectionConnection到p的槽是會執行的。只是並不執行在這個thread_proc的上下文當中。

如果想要這個執行緒可以接受槽。可以繼承使用Qthread類。

在類的run方法裡面呼叫this->exec。執行messageloop 。所以上面的寫法可以改成

QSonThread::run()

{

       p=new QObject

     this->exec()

}