Qt多線程編程總結(二)——QMutex

來源:互聯網
上載者:User

QMutex類提供的是線程之間的訪問順序化。

QMutex的目的是保護一個對象、資料結構或者程式碼片段,所以同一時間只有一個線程可以訪問它。(在Java術語中,它和同步關鍵字“synchronized”很相似)。例如,這裡有一個方法列印給使用者兩條訊息:

  void someMethod()  {     qDebug("Hello");     qDebug("World");  }  

如果同時在兩個線程中調用這個方法,結果的順序將是:

  Hello  Hello  World  World  

如果你使用了一個互斥量:

  QMutex mutex;  void someMethod()  {     mutex.lock();     qDebug("Hello");     qDebug("World");     mutex.unlock();  }  

用Java的術語,這段代碼應該是:

  void someMethod()  {     synchronized {       qDebug("Hello");       qDebug("World");     }  }  

然後同一時間只有一個線程可以運行someMethod並且訊息的順序也一直是正確的。當然,這隻是一個很簡單的例子,但是它適用於任何需要按特定頻率發生的情況。

但你在一個線程中調用lock(),其它線程將會在同一地點試圖調用lock()來阻塞,知道這個線程調用unlock()之後其它線程才會獲得這個鎖。lock()的一種非阻塞選擇是tryLock()。

實驗部分:

情形一:

#include <QtCore/QCoreApplication>#include <Qthread>#include <QTextStream>class MyThreadA : public QThread {  public:    virtual void run();  };  class MyThreadB: public QThread {  public:    virtual void run();  };int number=6;void MyThreadA::run(){  number *= 5;number /= 4;}  void MyThreadB::run(){number *= 3;number /= 2;} int main(int argc, char *argv[]){   QCoreApplication app(argc, argv);MyThreadA a;  MyThreadB b;  a.run();b.run(); a.terminate();b.terminate();QTextStream out(stdout);out<<number;return app.exec();} 

上述代碼,很簡單,寫了兩個線程,覆蓋了QThread的純虛函數run(),這兩個重構的run方法都是對全域變數number的操作,

主函數中順序調用這兩個方法,a.run()執行後number為7,b.run()執行後為10。

情形二:

#include <QtCore/QCoreApplication>#include <Qthread>#include <QTextStream>class MyThreadA : public QThread {  public:    virtual void run();  };  class MyThreadB: public QThread {  public:    virtual void run();  };int number=6;void MyThreadA::run(){  number *= 5;sleep(1);number /= 4;}  void MyThreadB::run(){number *= 3;sleep(1);number /= 2;} int main(int argc, char *argv[]){   QCoreApplication app(argc, argv);MyThreadA a;  MyThreadB b;  a.start();b.start();  a.wait();  b.wait(); QTextStream out(stdout);out<<number;return app.exec();} 

運行結果:

number=11;

利用QThread的方法start()同是開啟兩個線程,值得注意的是wait()函數,不能等待自己,這個是用來多個線程互動的,所以不能當sleep()用。這個函數是在主線程中被調用的時候阻塞了主線程。如果想在外部讓子線程暫停,最好的辦法是在子線程中設定一個標誌,在主線程中更改這個標誌,並在子線程的run函數中判斷,通過調用其保護函數sleep()來達到暫停目的了。

查看原始碼,即可有清楚的概念:

bool QThread::wait(unsigned long time){    Q_D(QThread);    QMutexLocker locker(&d->mutex);     if (d->id == GetCurrentThreadId()) {        qWarning("QThread::wait: Thread tried to wait on itself");     //當是自身時,直接返回false        return false;    }    if (d->finished || !d->running) //與這個線程對象關聯的線程已經結束執行(例如從run函數返回)。如果線程結束返回真值。如果線程還沒有開始也返回真值。        return true;    ++d->waiters;    locker.mutex()->unlock();    bool ret = false;    switch (WaitForSingleObject(d->handle, time)) {   //調用win的對象處理函數    case WAIT_OBJECT_0:    //核心對象被啟用,等待成功        ret = true;        break;    case WAIT_FAILED:        qErrnoWarning("QThread::wait: Thread wait failure");             break;    case WAIT_ABANDONED:    case WAIT_TIMEOUT:    default:        break;    }    locker.mutex()->lock();    --d->waiters;    if (ret && !d->finished) {                                  //雖然響應成功,但關聯對象未結束執行        // thread was terminated by someone else        d->terminated = true;                    QThreadPrivate::finish(this, false);    }    if (d->finished && !d->waiters) {    //關聯對象執行結束,並且等待數為零時,關閉控制代碼。        CloseHandle(d->handle);        d->handle = 0;    }    return ret;}

情形三:(Mutex 作用)

#include <QtCore/QCoreApplication>#include <Qthread>#include <QTextStream>#include <QMutex>class MyThreadA : public QThread {  public:    virtual void run();  };  class MyThreadB: public QThread {  public:    virtual void run();  };QMutex mutex;int number=6;void MyThreadA::run(){  mutex.lock();number *= 5;sleep(1);number /= 4;mutex.unlock();}  void MyThreadB::run(){mutex.lock();number *= 3;sleep(1);number /= 2;mutex.unlock();} int main(int argc, char *argv[]){   QCoreApplication app(argc, argv);MyThreadA a;  MyThreadB b;  a.start();b.start();  a.wait();  b.wait();  QTextStream out(stdout);out<<number;return app.exec();} 

運行結果:

number=10;

通過實驗結果可以看出,QMutex保護了全域變數,同一時間只有一個線程可以訪問它。

只得一提的是tryLock()的使用,若以上代碼換為mutex.tryLock();那麼執行結果可能為11,因為是試圖鎖定互斥量。如果鎖被得到,這個函數返回真。如果另一個進程已經鎖定了這個互斥量,這個函數返回假,而不是一直等到這個鎖可用為止。

且不能添上sleep()函數,否則提示 "A mutex must be unlocked in the same thread that locked it."的運行錯誤。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.