線程互斥html
多線程運行時,一般會訪問同一個變量,同一個數據結構,或者同一段代碼。所以,須要使用互斥技術來保護上述資源,確保多線程執行的正確性。安全
注:數據結構
咱們一般說某個函數是線程安全的,也就是由於該函數實現加入了線程互斥保護。多線程
4.一、QMutex函數
|
QMutex ( RecursionMode mode = NonRecursive )ui |
|
~QMutex ()this |
void.net |
lock ()線程 mutex加鎖,若是當前其餘線程已對該mutex加鎖了,則該調用被阻塞直到其餘線程釋放該mutex。htm |
bool |
tryLock () mutex加鎖,和lock不一樣的是,若是當前其餘線程已對該mutex加鎖了,則該調用會當即返回,而不被阻塞。 |
bool |
tryLock ( int timeout ) 同tryLock,和tryLock不一樣的是,若是當前其餘線程已對該mutex加鎖了,則該調用會等待一段時間,直到超時或者其餘線程釋放了mutex。 |
void |
unlock () mutex解鎖,釋放被鎖住的資源。 |
Mutex有兩種模式,用戶能夠在構造函數參數中指定。
Constant |
Value |
Description |
QMutex::Recursive |
1 |
In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made. 該模式下,一個線程能夠對mutex屢次lock,直到相應次數的unlock,調用後,該mutex才真正被unlock。 |
QMutex::NonRecursive |
0 |
In this mode, a thread may only lock a mutex once. 該模式下,mutex只能被lock一次。 |
實例:
QMutex mutex;
int number = 6;
void method1()
{
mutex.lock();
number *= 5;
number /= 4;
mutex.unlock();
}
void method2()
{
mutex.lock();
number *= 3;
number /= 2;
mutex.unlock();
}
4.一、QMutexLocker
|
QMutexLocker ( QMutex * mutex ) |
|
|
QMutex * |
mutex () const |
void |
relock () |
void |
unlock () |
QMutexLocker其實是對QMutex使用的一種簡化。
例如如下場景:
當某段代碼存在多個分支,在對QMutex加鎖後,須要在不一樣的分支路徑下都執行解鎖操做,才能保證Mutex關聯的資源能被其餘線程繼續訪問, 不然就出現死鎖。
QMutexLocker接收一個QMutex做爲參數,當建立QMutexLocker對象時,就對關聯的Mutex進行了Lock操做,直到該QMutexLocker對象被銷燬,相關的QMutex才被Unlock。
實例:
直接使用QMutex:
int complexFunction(int flag)
{
mutex.lock();
int retVal = 0;
switch (flag) {
case 0:
case 1:
mutex.unlock();
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0) {
mutex.unlock();
return -2;
}
retVal = status + flag;
}
break;
default:
if (flag > 10) {
mutex.unlock();
return -1;
}
break;
}
mutex.unlock();
return retVal;
}
使用QMutexLocker:
int complexFunction(int flag)
{
QMutexLocker locker(&mutex);
int retVal = 0;
switch (flag) {
case 0:
case 1:
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0)
return -2;
retVal = status + flag;
}
break;
default:
if (flag > 10)
return -1;
break;
}
return retVal;
}
固然,使用QMutexLocker時,也須要注意QMutexLocker對象的生存週期,不然可能會出現鎖時間過長,或者鎖住的資源過多。
4.三、QReadLocker、QWriteLocker、QReadWriteLocker
還有一種場景,咱們所保護的資源是具備讀寫權限的,多個線程能夠同時讀取某個資源,可是當存在寫操做,寫操做未完成時,就不容許其餘線程對該資源進行讀操做。
|
|
|
QReadWriteLock ( RecursionMode recursionMode ) |
|
|
void |
lockForRead () |
void |
lockForWrite () |
bool |
|
bool |
tryLockForRead ( int timeout ) |
bool |
|
bool |
tryLockForWrite ( int timeout ) |
void |
unlock () |
|
QReadLocker ( QReadWriteLock * lock ) |
|
~QReadLocker () |
QReadWriteLock * |
readWriteLock () const |
void |
relock () |
void |
unlock () |
|
QWriteLocker ( QReadWriteLock * lock ) |
|
|
QReadWriteLock * |
readWriteLock () const |
void |
relock () |
void |
unlock () |
實例:
QReadWriteLock lock;
void ReaderThread::run()
{
...
lock.lockForRead();
read_file();
lock.unlock();
...
}
void WriterThread::run()
{
...
lock.lockForWrite();
write_file();
lock.unlock();
...
}
4.四、QSemaphore
和QMutex不一樣的是,QSemaphore一次能夠對多個資源進行保護,
例如如下場景:
某工廠只有固定倉位,生產人員天天生產的產品數量不一,銷售人員天天銷售的產品數量也不一致。當生產人員生產P個產品時,就一次須要P個倉位,當銷售人員銷售C個產品時,就要求倉庫中有足夠多的產品才能銷售。
若是剩餘倉位沒有P個時,該批次的產品都不存入,噹噹前已有的產品沒有C個時,就不能銷售C個以上的產品,直到新產品加入後方可銷售。
這就是典型的生產者-消費者問題。
|
QSemaphore ( int n = 0 ) |
|
~QSemaphore () |
void |
acquire ( int n = 1 ) |
int |
available () const |
void |
release ( int n = 1 ) |
bool |
tryAcquire ( int n = 1 ) |
bool |
tryAcquire ( int n, int timeout ) |
實例:
QSemaphore sem(5); // sem.available() == 5 默認有5個產品
sem.acquire(3); // sem.available() == 2 銷售3個產品,成功
sem.acquire(2); // sem.available() == 0 銷售2個產品成功
sem.release(5); // sem.available() == 5 生產5個產品
sem.release(5); // sem.available() == 10 生產10個產品
sem.tryAcquire(1); // sem.available() == 9, returns true 消費1個產品,成功
sem.tryAcquire(250); // sem.available() == 9, returns false 企圖銷售250個產品,失敗,由於當前只剩下14個產品
4.五、QWaitCondition