http://blog.csdn.net/mznewfacer/article/details/6965799
QMutex類
一個線程可以鎖定互斥量,並且在它鎖定之后,其它線程就不能再鎖定這個互斥量了,試圖這樣做的線程都會被阻塞直到互斥量被釋放
class MyClass { public: void doStuff( int ); private: QMutex mutex; int a; int b; }; // 這里設置a為c,b為c*2。 void MyClass::doStuff( int c ) { mutex.lock(); a = c; b = c * 2; mutex.unlock(); }
QWaitCondition
線程等待的條件QWaitCondition指出發生了什么事情,阻塞將一直持續到這種事情發生。當某種事情發生了,QWaitCondition可以喚醒等待這一事件的線程之一或全部
#include <qapplication.h> #include <qpushbutton.h> // 全局條件變量 QWaitCondition mycond; // Worker類實現 class Worker : public QPushButton, public QThread { Q_OBJECT public: Worker(QWidget *parent = 0, const char *name = 0) : QPushButton(parent, name) { setText("Start Working"); // 連接從QPushButton繼承來的信號和我們的slotClicked()方法 connect(this, SIGNAL(clicked()), SLOT(slotClicked())); // 調用從QThread繼承來的start()方法……這將立即開始線程的執行 QThread::start(); } public slots: void slotClicked() { // 喚醒等待這個條件變量的一個線程 mycond.wakeOne(); } protected: void run() { // 這個方法將被新創建的線程調用…… while ( TRUE ) { // 鎖定應用程序互斥鎖,並且設置窗口標題來表明我們正在等待開始工作 qApp->lock(); setCaption( "Waiting" ); qApp->unlock(); // 等待直到我們被告知可以繼續 mycond.wait(); // 如果我們到了這里,我們已經被另一個線程喚醒……讓我們來設置標題來表明我們正在工作 qApp->lock(); setCaption( "Working!" ); qApp->unlock(); // 這可能會占用一些時間,幾秒、幾分鍾或者幾小時等等,因為這個一個和GUI線程分開的線程,在處理事件時,GUI線程不會停下來…… do_complicated_thing(); } } }; // 主線程——所有的GUI事件都由這個線程處理。 int main( int argc, char **argv ) { QApplication app( argc, argv ); // 創建一個worker……當我們這樣做的時候,這個worker將在一個線程中運行 Worker firstworker( 0, "worker" ); app.setMainWidget( &worker ); worker.show(); return app.exec(); }
只要你按下按鈕,這個程序就會喚醒worker線程,這個線程將會進行並且做一些工作並且然后會回來繼續等待被告知做更多的工作。如果當按鈕被按下時,worker線程正在工作,那么就什么也不會發生。當線程完成了工作並且再次調用QWaitCondition::wait(),然后它就會被開始。
QWaitCondition
QWaitCondition 允許線程在某些情況發生時喚醒另外的線程。一個或多個線程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()設置一個條件。wakeOne()隨機喚醒一個,wakeAll()喚醒所有。
下面的例子中,生產者首先必須檢查緩沖是否已滿(numUsedBytes==BufferSize),如果是,線程停下來等待 bufferNotFull條件。如果不是,在緩沖中生產數據,增加numUsedBytes,激活條件 bufferNotEmpty。使用mutex來保護對numUsedBytes的訪問。另外,QWaitCondition::wait() 接收一個mutex作為參數,這個mutex應該被調用線程初始化為鎖定狀態。在線程進入休眠狀態之前,mutex會被解鎖。而當線程被喚醒 時,mutex會處於鎖定狀態,而且,從鎖定狀態到等待狀態的轉換是原子操作,這阻止了競爭條件的產生。當程序開始運行時,只有生產者可以工作。消費者被 阻塞等待bufferNotEmpty條件,一旦生產者在緩沖中放入一個字節,bufferNotEmpty條件被激發,消費者線程於是被喚醒。
const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QWaitCondition bufferNotEmpty; QWaitCondition bufferNotFull; QMutex mutex; int numUsedBytes = 0; class Producer : public QThread { public: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex); mutex.unlock(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; mutex.lock(); ++numUsedBytes; bufferNotEmpty.wakeAll(); mutex.unlock(); } } class Consumer : public QThread { public: void run(); }; void Consumer::run() { for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex); mutex.unlock(); fprintf(stderr, "%c", buffer[i % BufferSize]); mutex.lock(); --numUsedBytes; bufferNotFull.wakeAll(); mutex.unlock(); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; }