1. 程式人生 > >Qt之QThread

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
下面來看下優先順序中的各個列舉值:

m沉默01

二、主執行緒、次執行緒

在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