生活随笔
收集整理的這篇文章主要介紹了
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中多线程间的互斥的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。