日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt中多线程间的互斥

發布時間:2025/4/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt中多线程间的互斥 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1 多線程間的互斥
      • 1.1 生產消費者問題
      • 1.2 QMutex
      • 1.3 死鎖問題
      • 1.4 信號量

1 多線程間的互斥

值得思考的問題:

  • 多個線程間除了在時序上可能產生依賴,在其它方面是否也可能產生依賴呢?

1.1 生產消費者問題

生產消費者問題如下:

  • 有n個生產者同時制造產品,并把產品存入倉庫中。
  • 有m個消費者同時需要從倉庫中取出產品。
  • 規則:
    • 當倉庫未滿,任意生產者可以存入產品。
    • 當倉庫未空,任意消費者可以取出產品。

生活中的互斥的例子:

編程實驗:生產消費者問題

#include <QtCore/QCoreApplication> #include <QThread> #include <QDebug>static QString g_store;class Producer : public QThread { protected:void run(){int count = 0;while(true){g_store.append(QString::number((count++) % 10));qDebug() << objectName() << " : " + g_store;msleep(1);}} };class Customer : public QThread { protected:void run(){while( true ){if( g_store != "" ){g_store.remove(0, 1);qDebug() << objectName() << " : " + g_store;}msleep(1);}} };int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);Producer p;Customer c;p.setObjectName("Producer");c.setObjectName("Customer");p.start();c.start();return a.exec(); }

上面的程序有可能由于讀寫沖突,會直接導致應用程序崩潰。

1.2 QMutex

臨界資源(Critical Resoruce):

  • 每次只允許一個線程進行訪問(讀/寫)的資源。

線程間的互斥(競爭):

  • 多個線程在同一時刻都需要訪問臨界資源。

QMutex類是一把線程鎖,保證線程間的互斥:

  • 利用線程鎖能夠保證臨界資源的安全性。

QMutext中的關鍵成員函數:

  • void lock():
    • 當鎖空閑時,獲取鎖并繼續執行。
    • 當鎖被獲取時,阻塞并等待鎖釋放。
  • void unlock():
    • 釋放鎖(同一把鎖的獲取和釋放鎖必須在同一線程中成對出現)。

QMutext使用示例:

編程實驗:線程鎖解決生產消費者問題

#include <QtCore/QCoreApplication> #include <QThread> #include <QMutex> #include <QDebug>static QMutex g_mutex; static QString g_store;class Producer : public QThread { protected:void run(){int count = 0;while(true){g_mutex.lock();g_store.append(QString::number((count++) % 10));qDebug() << objectName() << " : " + g_store;g_mutex.unlock();msleep(1);}} };class Customer : public QThread { protected:void run(){while( true ){g_mutex.lock();if( g_store != "" ){g_store.remove(0, 1);qDebug() << objectName() << " : " + g_store;}g_mutex.unlock();msleep(1);}} };int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);Producer p;Customer c;p.setObjectName("Producer");c.setObjectName("Customer");p.start();c.start();return a.exec(); }

1.3 死鎖問題

問題:

  • 程序有多少臨界資源?需要多少把鎖?

一般性原則:

  • 每一個臨界資源都需要一個線程鎖進行保護!

看一下如下代碼:

如上代碼會發生死鎖。

線程的死鎖概念:

  • 線程間相互等待臨界資源而造成彼此無法繼續執行。

發生死鎖的條件:

  • 系統中存在多個臨界資源且臨界資源不可搶占。
  • 線程需要多個臨界資源才能繼續執行。

死鎖的避免:

  • 對所有的臨界資源都分配一個唯一的序號(r1,r2,… , rn)。
  • 對應的線程鎖也分配同樣的序號(m1,m2,…,mn)。
  • 系統中的每個線程按照嚴格遞增的次序請求資源。

#include <QtCore/QCoreApplication> #include <QThread> #include <QMutex> #include <QDebug>QMutex g_mutex_1; QMutex g_mutex_2;class ThreadA : public QThread { protected:void run(){while( true ){g_mutex_1.lock();qDebug() << objectName() << "get m1";g_mutex_2.lock();qDebug() << objectName() << "get m2";qDebug() << objectName() << "do work ...";g_mutex_2.unlock();g_mutex_1.unlock();sleep(1);}} };class ThreadB : public QThread { protected:void run(){while( true ){g_mutex_1.lock();qDebug() << objectName() << "get m2";g_mutex_2.lock();qDebug() << objectName() << "get m1";qDebug() << objectName() << "do work ...";g_mutex_2.unlock();g_mutex_1.unlock();sleep(1);}} };int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);ThreadA ta;ThreadB tb;ta.setObjectName("ta");tb.setObjectName("tb");ta.start();tb.start();return a.exec(); }

1.4 信號量

信號量的概念:

  • 信號量是特殊的線程鎖。
  • 信號量允許N個線程同時訪問臨界資源。
  • Qt中直接支持信號量(QSemaphore)。

QSemaphore使用示例:

編程實驗:再論生產消費者問題

#include <QtCore/QCoreApplication> #include <QThread> #include <QSemaphore> #include <Qdebug>const int SIZE = 5; unsigned char g_buff[SIZE] = {0}; QSemaphore g_sem_free(SIZE); QSemaphore g_sem_used(0);class Producer : public QThread { protected:void run(){while( true ){int value = qrand() % 256;g_sem_free.acquire();for(int i=0; i<SIZE; i++){if( !g_buff[i] ){g_buff[i] = value;qDebug() << objectName() << " generate: {" << i << ", " << value << "}";break;}}g_sem_used.release();sleep(2);}} };class Customer : public QThread { protected:void run(){while( true ){g_sem_used.acquire();for(int i=0; i<SIZE; i++){if( g_buff[i] ){int value = g_buff[i];g_buff[i] = 0;qDebug() << objectName() << " consume: {" << i << ", " << value << "}";break;}}g_sem_free.release();sleep(1);}} };int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);Producer p1;Producer p2;Producer p3;p1.setObjectName("p1");p2.setObjectName("p2");p3.setObjectName("p3");Customer c1;Customer c2;c1.setObjectName("c1");c2.setObjectName("c2");p1.start();p2.start();p3.start();c1.start();c2.start();return a.exec(); }

注意:嚴格來說g_buff必須加鎖。


參考資料:

  • QT實驗分析教程
  • 總結

    以上是生活随笔為你收集整理的Qt中多线程间的互斥的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。