天天看點

Qt之多線程(一)

            Qt 是一種基于 C++ 的跨平台 GUI 系統,能夠提供給使用者構造圖形使用者界面的強大功能。為了滿足使用者構造複雜圖形界面系統的需求,Qt 提供了豐富的多線程程式設計支援。Qt 主要從三個方面對多線程程式設計提供支援:一、構造了一些基本的與平台無關的線程類;二、送出使用者自定義事件的 Thread-safe 方式;三、多種線程間同步機制,如信号量,全局鎖。

1、QThread

       QThread提供了與平台無關的線程。一個QThread代表單獨運作于程式的線程。它與程序中的其他線程共享資料,在多任務作業系統中單獨運作。線程使用run()方法開始執行,在run()方法中調用exec()開始事件循環。我們可以通過繼承QThread并且重寫run()函數編寫一個線程。例如:

//mythread.h

#ifndef MYTHREAD_H

#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread

{

public:

MyThread();

MyThread(int count);

void run();

private:

int count;

};

#endif // MYTHREAD_H  

//mythread.cpp

#include "mythread.h"

#include "QThread"

#include <QDebug>

MyThread::MyThread()

{

}

MyThread::MyThread(int count)

{

this->count = count;

}

void MyThread::run()

{

while(count<20000)//為了檢視結果盡量設定大一些

{

qDebug()<< QThread::currentThread()->objectName()<<this->count++;

}

}

//main.cpp

#include <QtCore/QCoreApplication>

#include "mythread.h"

#include <QDebug>

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

qDebug()<< "Main Start";

MyThread myThread1(0);

myThread1.setObjectName("MyThread1");

myThread1.start();

MyThread myThread2(0);

myThread2.setObjectName("MyThread2");

myThread2.start();

int c = 0;

while(c < 20000)//為了檢視結果盡量設定大一些

{

qDebug()<< "Main Thread"<< c++;

}

return a.exec();

}

在main函數中我定義了兩個線程,并分别設定了線程名稱。運作過程中有三個線程會可能同時運作。主函數線程,myThread1線程,myThread2線程。可以從運作結果看出:

g

Main Start

Main Thread 0

Main Thread 1

Main Thread 2

Main Thread 3

Main Thread 4

Main Thread 5

....

Main Thread 1040

Main Thread 1041

Main Thread 1042

Main Thread 1043

Main Thread 1044

"MyThread2" 0

"MyThread2" 1

"MyThread2" 2

"MyThread2" 3

"MyThread2" 4

"MyThread2" 5

"MyThread2" 6

.....

"MyThread2" 1158

"MyThread2" 1159

"MyThread2" 1160

"MyThread2" 1161

"MyThread2" 1162

"MyThread1" 0

"MyThread1" 1

"MyThread1" 2

"MyThread1" 3

"MyThread1" 4

"MyThread1" 5

.......

Main Thread 19990

Main Thread 19991

Main Thread 19992

Main Thread 19993

Main Thread 19994

Main Thread 19995

Main Thread 19996

Main Thread 19997

Main Thread 19998

Main Thread 19999

QThread包含一個枚舉類型

enum    Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, ..., InheritPriority } 這個枚舉類型表示作業系統如何應安排新建立的線程

QThread::IdlePriority    0    安排隻是CPU空閑時在運作

QThread::LowestPriority    1    安排最低優先級

QThread::LowPriority    2    安排低優先級

QThread::NormalPriority    3    安排正常優先級

QThread::HighPriority    4    安排高優先級

QThread::HighestPriority    5    安排高于最高.

QThread::TimeCriticalPriority    6    盡可能安排.

QThread::InheritPriority    7    安排使用繼承父類優先級(預設)

公共方法:

QThread ( QObject * parent = 0 )    構造函數,這個線程知道調用它的start函數時才會執行

~QThread ()                析構函數

void    exit ( int returnCode = 0 )    調用此方法後,線程将退出事件循環并且傳回從調用的QEventLoop::exec()的一個傳回值

bool    isFinished () const        傳回線程是否已完成

bool    isRunning () const        傳回線程是否正在運作

Priority    priority () const    傳回線程的優先級.如果線程沒有運作,将傳回InheritPriority

void    setPriority ( Priority priority )  為正在運作的線程設定優先級,如果線程未運作,将不做任何操作,立即傳回.

void    setStackSize ( uint stackSize )    設定線程棧的大小的最大值,如果線上程中進行遞歸調用,那麼可以通過增加堆得大小來保證遞歸不會溢出。

uint    stackSize () const        傳回目前線程棧的最大值

bool    wait ( unsigned long time = ULONG_MAX )阻塞線程直到線程結束運作或Time已經過去

槽:

void    quit ()        退出事件循環,等同于調用線程的exit(0),如果線程沒有事件循環則什麼也不做。

void    start ( Priority priority = InheritPriority )開始執行線程

void    terminate ()    終止線程,線程是否立即被終止,依賴于作業系統.警告:這個函數是危險地,不被鼓勵使用

信号:

void    finished ()    當線程結束運作時此信号被發射

void    started ()    當線程開始運作時此信号被發射

void    terminated ()    當線程被終止時此信号被發射

靜态成員:

QThread *    currentThread ()    傳回指向目前線程的指針

Qt::HANDLE    currentThreadId ()    傳回目前線程的句柄

int    idealThreadCount ()        傳回目前作業系統能運作線程的數量   

void    yieldCurrentThread ()        讓出CPU給其他線程,對于運作哪個線程完全決定于作業系統。

2、QRunnable

       QRunable是所有可運作對象的基類。代表需要執行的一個任務或一段代碼的接口。可以通過QThreadPool單獨執行線程。QThreadPool可以自動删除QRunable如果此可運作對象的autoDelete()方法傳回ture的話。我們可以使用setAutoDelete()函數設定auto-deletion辨別.

總之QRunnable提供了簡潔有效的可運作對象的建立

      優點: 建立過程簡潔, 使用友善, 配合着自身的autoDelete特性, 有點“招之即來, 揮之即去”的感覺.

      缺點: 無法實時提供自身的運作狀态.

3、QThreadPool

      線程池,用于管理一個線程的集和。

      線程池用于管理和回收線程對象以減少程式中建立線程的花費。

      每個Qt應用都有一個全局的QThreadPool對象,通過QThreadPool::globalInstance()擷取

屬性:

activeThreadCount : const int    線程池中活動的線程個數

expiryTimeout : int        線程經過expiryTimeout未被使用将被認為expired并且exit。這種線程可以重新被restart.預設過期時間是30000毫秒即30秒。如果過期時間設定為負的,那麼被建立的線程将永遠不會exit直到線程池銷毀。設定過期時間不會影響到已經在運作的線程。隻有新建立的線程使用這個過期時間。是以推薦在建立線程池後立即設定過期時間.

maxThreadCount : int        線程池中允許最大的線程數量。線程池最少允許一個線程,即使這個值被設定為0或負數.預設的最大線程數量是QThread::idealThreadCount()

公共方法:

QThreadPool ( QObject * parent = 0 )    

~QThreadPool ()

int    activeThreadCount () const    傳回activeThreadCount屬性值

int    expiryTimeout () const        傳回expiryTimeout屬性值

int    maxThreadCount () const        傳回maxThreadCount屬性值

void    releaseThread ()

void    reserveThread ()    存儲一個線程,

void    setExpiryTimeout ( int expiryTimeout )

void    setMaxThreadCount ( int maxThreadCount )

void    start ( QRunnable * runnable, int priority = 0 )    存儲一個線程并且運作可執行對象并且将可執行對象加入到運作隊列中,如果這個線程沒有使目前線程數超過最大線程數。

bool    tryStart ( QRunnable * runnable )    嘗試存儲一個線程并且運作可執行對象。如果沒有這時沒有時間片可以運作線程,那麼這個方法将什麼也不做。否則這個可執行對象線程将使用一個可運作線程立即運作。

void    waitForDone ()    等待所有線程退出,并且移除所有線程池中線程.

靜态函數

QThreadPool * QThreadPool::globalInstance ()    擷取全局線程對象

QThreadPool::globalInstance()->start(Runable執行個體);

繼續閱讀