Qt之QThread
https://wenku.baidu.com/view/eb8b4583a216147916112843.html
一、執行緒管理
1、執行緒啟動
void start(Priority priority = InheritPriority)
呼叫後會執行run()函式,但在run()函式執行前會發射訊號started(),作業系統將根據優先順序引數排程執行緒。如果執行緒已經在執行,那麼這個函式什麼也不做。優先順序引數的效果取決於作業系統的排程策略。特別是那些不支援執行緒優先順序的系統優先順序將會被忽略(例如在Linux中,更多細節請參考http://linux.die.net/man/2/sched_setscheduler)。
2、執行緒執行
int exec()
進入事件迴圈並等待直到呼叫exit(),返回值是通過呼叫exit()來獲得,如果呼叫成功則範圍0。
virtual void run();
執行緒的起點,在呼叫start()之後,新建立的執行緒就會呼叫這個函式,預設實現呼叫exec(),大多數需要重新實現這個功能,便於管理自己的執行緒。該方法返回時,該執行緒的執行將結束。
3、執行緒退出
(1)void quit()
告訴執行緒事件迴圈退出,返回0表示成功,相當於呼叫了QThread::exit(0)。
(2)void exit(int returnCode = 0)
告訴執行緒事件迴圈退出。
呼叫這個函式後,執行緒離開事件迴圈後返回,QEventLoop::exec()返回returnCode,
按照慣例0表示成功,任何非0值表示失敗。
(3)void terminate()
終止執行緒,執行緒可能會立即被終止也可能不會,這取決於作業系統的排程策略,使用terminate()之後再使用QThread::wait()確保萬無一失。
當執行緒被終止後,所有等待中的執行緒將會被喚醒。
警告:此功能比較危險,不鼓勵使用。執行緒可以在程式碼執行的任何點被終止。執行緒可能在更新資料時被終止,從而沒有機會來清理自己,解鎖等等。。。總之,只有在絕對必要時使用此功能。
建議:一般情況下,都在run函式裡面設定一個識別符號,可以控制迴圈停止。然後才呼叫quit函式,退出執行緒。
4、執行緒等待
void msleep(unsigned long msecs) 強制當前執行緒睡眠msecs毫秒
void sleep(unsigned long secs) 強制當前執行緒睡眠secs秒
void usleep(unsigned long usecs) 強制當前執行緒睡眠usecs微秒
bool wait(unsigned long time = ULONG_MAX); 執行緒將會被阻塞,等待time毫秒。和sleep不同的是,如果執行緒退出,wait會返回。
5、執行緒狀態
bool isFinished() const 執行緒是否結束
bool isRunning() const 執行緒是否正在執行
6、執行緒優先順序
(1)void setPriority(Priority priority)
這個函式設定正在執行執行緒的優先順序。如果執行緒沒有執行,此功能不執行任何操作並立即返回。使用的start()來啟動一個執行緒具有特定的優先順序。
優先順序引數可以是QThread::Priority列舉除InheritPriortyd的任何值。
(2)Priority priority() const
下面來看下優先順序中的各個列舉值:
二、主執行緒、次執行緒
在Qt之執行緒(QThread)一節中我介紹了QThread 的兩種使用方法:
1、子類化 QThread(不使用事件迴圈)。
這是官方手冊、例子以及相關書籍中都介紹的一種常用的方法。
a. 子類化 QThread
b. 過載 run 函式,run函式內有一個while或for的死迴圈(模擬耗時操作)
c. 設定一個標記為來控制死迴圈的退出。
2、子類化 QObject
a. 子類化 QObject
b. 定義槽函式
c. 將該子類的物件moveToThread到新執行緒中
run 對於執行緒的作用相當於main函式對於應用程式。它是執行緒的入口,run的開始和結束意味著執行緒的開始和結束。
採用這兩種做法,毫無疑問都會在次執行緒中執行(這裡說的是,run中的邏輯以及子類化QObject後連線通過moveToThread然後連線到QThread的started()訊號的槽函式,這個下面會詳細講解)。
那麼,執行緒中的槽函式是怎麼執行的呢?
說到訊號與槽,大家應該再熟悉不過了,包括我,特別喜歡使用自定義訊號與槽,感覺用起來特方便、特棒。。。
經常使用,你能否100%的使用正確?你瞭解它的高階用法嗎?
1、你是否在多次connect,還發現不了為什麼槽函式會執行那N多次。
2、你是否瞭解disconnect
3、你是否瞭解connect中的第五個引數 Qt::ConnectionType
關於connect、disconnect訊號、槽的使用可參考:Qt之訊號與槽。既然談到執行緒這裡需要重點說下Qt::ConnectionType(訊號與槽的傳遞方式)
舉例:
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0);
public slots:
void start();
};
#endif // MYOBJECT_H
MyObject.cpp
#include "MyObject.h"
#include
#include
MyObject::MyObject(QObject *parent)
: QObject(parent)
{
}
void MyObject::start()
{
qDebug() << QString("my object thread id:") << QThread::currentThreadId();
}
main.cpp
#include "MyObject.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << QString("main thread id:") << QThread::currentThreadId();
MyObject object;
QThread thread;
object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()));
thread.start();
return a.exec();
}
檢視執行結果:
"main thread id:" 0xf08
"my object thread id:" 0x216c
顯然主執行緒與槽函式的執行緒是不同的(你可以多次嘗試,屢試不爽。。。),因為moveToThread後MyObject所在的執行緒為QThread,繼上面介紹的thread.start()執行後首先會發射started()訊號,也就是說started()訊號發射是在次執行緒中進行的,所以無論採取Qt::AutoConnection、Qt::DirectConnection、Qt::QueuedConnection哪種連線方式,主執行緒與槽函式的執行緒都是不同的。
1.程式碼修改如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::DirectConnection);
thread.start();
檢視執行結果:
"main thread id:" 0x2688
"my object thread id:" 0x2110
顯然主執行緒與槽函式的執行緒是不同的,MyObject所依附的執行緒為主執行緒(因為註釋掉了moveToThread),繼上面介紹的Qt::DirectConnection(無論槽函式所屬物件在哪個執行緒,槽函式都在發射訊號的執行緒內執行)。也就是說started()訊號發射是在次執行緒中進行的,槽函式也是在次執行緒中進行的,所以主執行緒與槽函式的執行緒是不同的。
2.程式碼修改如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::QueuedConnection);
thread.start();
檢視執行結果:
"main thread id:" 0x24ec
"my object thread id:" 0x24ec
顯然主執行緒與槽函式的執行緒是相同的,繼上面介紹的Qt::QueuedConnection(槽函式在接收者所依附執行緒執行)。也就是說started()訊號發射是在次執行緒中進行的,但MyObject所依附的執行緒為主執行緒(因為註釋掉了moveToThread),所以主執行緒與槽函式的執行緒必然是相同的。
3.程式碼修改如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::AutoConnection);
thread.start();
檢視執行結果:
"main thread id:" 0x2700
"my object thread id:" 0x2700
顯然主執行緒與槽函式的執行緒是相同的,MyObject所依附的執行緒為主執行緒(因為註釋掉了moveToThread),繼上面介紹的Qt::AutoConnection(如果訊號在接收者所依附的執行緒內發射,則等同於直接連線。如果發射訊號的執行緒和接受者所依附的執行緒不同,則等同於佇列連線。)。因為started()訊號和MyObject依附的執行緒不同,所以結果和Qt::QueuedConnection對應的相同,所以主執行緒與槽函式的執行緒是相同的。
基本就介紹到這裡,QThread使用和上面的大同小異,run裡面執行的程式碼都是在次執行緒中,如果是QThead的槽函式,那麼結論同上!
本文轉載自:作者:一去丶二三裡 原文:http://blog.sina.com.cn/s/blog_a6fb6cc90102vs8z.html