1、先看一些執行緒相關的類
qthread
提供了開始乙個新執行緒的方法
qthreadstorage
提供逐執行緒資料儲存
qmutex
互斥鎖qmutexlocker
自動鎖(在建構函式中自動對mutex進行加鎖,在析構函式中進行解鎖。需要用到mutable在const函式中修改被定義的非const變數)
qreadwriterlock
讀寫鎖qreadlocker&qwritelocker
自動對讀寫鎖加鎖解鎖
qsemaphore
訊號量qwaitcondition
條件變數
2、建立乙個簡答的執行緒,run()必須被重寫,因為它是純虛函式。
class mythread : public qthread ;
void mythread::run() ;
跟c++不同的是,qt的exec()必須在主線程,即main()函式中,因為gui執行緒預設是主線程。
跟c++類似的是,用三把鎖和條件變數保護共享資料訪問。
2.1 讀寫鎖 qreadwriterlock
qreadwritelock lock;
void readerthread::run()
void writerthread::run()
2.2 訊號量qsemaphore ,相比於互斥鎖,訊號量能保護一定數量的相同資源。
下面用qsemaphore 控制線程對環形緩衝區資源的訪問
const int datasize = 100000;
const int buffersize = 8192;
char buffer[buffersize];
qsemaphore freebytes(buffersize);
qsemaphore usedbytes;
class producer : public qthread
;void producer::run()
}class consumer : public qthread
;void consumer::run()
fprintf(stderr, "\n");
}int main(int argc, char *ar**)
2.3 qwaitcondition 類似於c++中的條件變數,例項化之後,利用wait()阻塞,weakone / weakall類似於c++的notify_one/all。
const int datasize = 100000;
const int buffersize = 8192;
char buffer[buffersize];
qwaitcondition buffernotempty;
qwaitcondition buffernotfull;
qmutex mutex;
int numusedbytes = 0;
class producer : public qthread
;void producer::run()
}class consumer : public qthread
;void consumer::run()
fprintf(stderr, "\n");
}int main(int argc, char *ar**)
3、可重入和執行緒安全
「可重入」與「執行緒安全」被用來說明乙個函式如何用於多執行緒程式。假如乙個類的任何函式在此類的多個不同的例項上,可以被多個執行緒同時呼叫,那麼這個類被稱為是「可重入」的。假如不同的執行緒作用在同乙個例項上仍可以正常工作,那麼稱之為「執行緒安全」的。
大多數c++類天生就是可重入的,因為它們典型地僅僅引用成員資料。任何執行緒可以在類的乙個例項上呼叫這樣的成員函式,只要沒有別的執行緒在同乙個例項上呼叫這個成員函式。舉例來講,下面的temp類是可重入的。
class temp
void increment()
void decrement()
int value() const
private:
int n;
};
但是上述類並不能保證執行緒的安全,因為自增自減並不是原子(atomic)操作,那麼就有可能被擴充套件成以下原子指令:
變數進入暫存器》增加/減少暫存器的值 》再把暫存器額值寫回記憶體之中。
問題會發生在兩個寫者執行緒都使用了舊值,然後在暫存器中增值,寫操作重疊,導致變數只增加了一次。所以,對資源的訪問應該序列化,執行上面三個步驟的時候不應該中斷。使用互斥鎖或者自動鎖是為了讓執行緒安全。
class counter
void increment()
void decrement()
int value() const
private:
mutable qmutex mutex;
int n;
};
4、多執行緒和隱含共享
qt許多值型別使用了所謂的隱含共享(implicit sharing)來優化效能。原理比較簡單,共享類包含乙個指向共享資料塊的指標,這個資料塊中包含了真正原資料與乙個引用計數。把深拷貝轉化為乙個淺拷貝,從而提高了效能。如果深入觀察,假如物件需要對資料進行修改,而引用計數大於1,那麼它應該先detach()。以使得它修改不會對別的共享者產生影響,既然修改後的資料與原來的那份資料不同了,因此不可能再共享了,於是它先執行深拷貝,把資料取回來,再在這份資料上進行修改。例如:
void qpen::setstyle(qt::penstyle style)
void qpen::detach()
翻譯qt手冊原文就是:「隱含共享類可以安全地跨執行緒拷貝,如同別的值型別一樣。它們是完全可重入的。隱含共享真的是"implicit"。它使用組合語言實現了原子性引用計數操作,比用mutex效率高。假如你在多個執行緒中同進訪問相同物件,你也需要用mutex來序列化訪問順序,就如同其他可重入物件那樣。總的來講,隱含共享真的給」隱含「掉了,在多執行緒程式中,你可以把它們看成是一般的,非共享的,可重入的型別,這種做法是安全的。」
5、qt下的p-c模型:
注意:1)生產者首先必須檢查緩衝是否已滿(numusedbytes==buffersize),如果是,執行緒停下來等待buffernotfull條件。如果不是,在緩衝中生產資料,增加numusedbytes,啟用條件 buffernotempty。
2)使用mutex來保護對numusedbytes的訪問。
而且,從鎖定狀態到等待狀態的轉換是原子操作,這阻止了競爭條件的產生。當程式開始執行時,只有生產者可以工作。消費者被阻塞等待buffernotempty條件,一旦生產者在緩衝中放入乙個位元組,buffernotempty條件被激發,消費者執行緒於是被喚醒。
const int datasize = 100000;
const int buffersize = 8192;
char buffer[buffersize];
qsemaphore freebytes(buffersize); //producer執行緒在此區域寫入資料,初始資源數量為buffersize
qsemaphore usedbytes; //consumer執行緒讀取此區域的資料,初始資源數量為0
class producer : public qthread
;//生產者每acquire一次就,使用掉buffer個資源中的乙個,而寫入的字元存入到buffer陣列中
//從而消費者可用讀取字元,從而消費者獲取乙個資源
void producer::run()
}class consumer : public qthread
;void consumer::run()
fprintf(stderr, "\n");
}int main(int argc, char* ar**)
再比如下面這個例子:
4 // 全域性條件變數
5 qwaitcondition mycond;
6 7 // worker類實現
8 class worker : public qpushbutton, public qthread
9
24 25 public slots:
26 void slotclicked()
27
31 32 protected:
33 void run()
34
54 }
55 };
56 57 // 主線程——所有的gui事件都由這個執行緒處理。
58 int main( int argc, char **ar** )
59
70
好用的臨時郵箱十分鐘郵箱推薦(親測)
為什麼要使用臨時郵箱?由於某些地方在註冊帳戶時需要驗證您的電子郵件,但是在您使用經常使用的電子郵件位址註冊後,幾天之內就會出現大量垃圾郵件。有時,您可能需要註冊一些 或其他內容。並且此行為只是偶然的或暫時的。也許您以後將不再使用它,但是註冊時通常需要填寫電子郵件位址,並且您不想使用真實的電子郵件位址...
QT多執行緒的學習
qt通過三種形式提供了對執行緒的支援。它們分別是,一 平台無關的執行緒類,二 執行緒安全的事件投遞,三 跨執行緒的訊號 槽連線。這使得開發輕巧的多執行緒qt程式更為容易,並能充分利用多處理器機器的優勢。多執行緒程式設計也是乙個有用的模式,它用於解決執行較長時間的操作而不至於使用者介面失去響應。在qt...
QT下的多執行緒
一.多執行緒的使用 繼承qthread類,重寫protected void run 函式,則此run函式即為多執行緒將執行的函式,ui類組合此類,呼叫start 函式即開啟此執行緒,並執行run函式 h class test1 public qthread cpp void test1 run vo...