Qt中提供了 QReadWriteLock 類,我們可以方便的使用讀寫鎖。
讀寫鎖 是指 讀鎖 和 寫鎖 。適用於多個線程讀操作比較頻繁,而寫操作不頻繁的場景中。
它能夠保證多個線程讀操作訪問資源時同時進行,而寫入操作時阻塞讀操作。也就是我們常說的,讀共享 和 寫獨佔 。
1. 讀共享和寫獨佔
讀共享 :
- 當其他線程佔用讀鎖的時候,如果其他線程請求讀鎖,會立即獲得。
- 當其他線程佔用讀鎖的時候,如果其他線程請求寫鎖,會阻塞等待讀鎖的釋放。
寫獨佔 :
- 當其他線程佔用寫鎖的時候,如果其他線程請求讀鎖,會阻塞等待寫鎖的釋放。
- 當其他線程佔用寫鎖的時候,如果其他線程請求寫鎖,會阻塞等待寫鎖的釋放。
2. 讀寫優先級
Qt的 QReadWriteLock 默認優先級是寫優先,即寫鎖的優先級>讀鎖。
舉個例子,比如當線程A佔用寫鎖的時候,線程B請求讀鎖,阻塞等待;線程C請求寫鎖,阻塞等待。那麼當線程A釋放寫鎖的時候,此時線程C會佔用讀寫鎖,因爲寫的優先級大於讀的優先級。
QReadWriteLock 中常用的函數如下:
- lockForRead() ; 請求讀鎖
- lockForWrite() ; 請求寫鎖
- tryLockForRead() ; 嘗試請求讀鎖,非阻塞函數,可以設置超時時間。
- tryLockForWrite() ; 嘗試請求寫鎖,非阻塞函數,可以設置超時時間。
- unlock() ; 解鎖(解讀鎖和解寫鎖,均使用該函數)
下面爲讀寫鎖的簡單使用:
讀線程:
class ReadThread : public QThread
{
public:
void run(void){
while (1){
// 讀鎖
readWriteLock.lockForRead();
qDebug() << "Read Thread: " << QThread::currentThreadId() \
<< ", Number is " << g_number;
readWriteLock.unlock();
QThread::msleep(100);
}
}
};
寫線程:
class WriteThread : public QThread
{
public:
void run(void){
while (1) {
// 寫鎖
readWriteLock.lockForWrite();
g_number++;
readWriteLock.unlock();
QThread::msleep(500);
}
}
};
調用部分:
// 創建並開啓寫入線程
WriteThread writeThread;
writeThread.start();
// 創建並開啓讀線程
ReadThread readThread[5];
for (int i=0; i<5; ++i)
readThread[i].start();
// 等待線程結束
writeThread.wait();
for (int i=0; i<5; ++i)
readThread[i].wait();
本例子中, g_number 爲一個全局變量,是共享資源;啓動5個線程讀操作,1個線程寫操作。每隔500ms進行一次寫操作,每個線程每隔100ms進行一次讀操作。
同互斥鎖(互斥量)一樣,讀寫鎖也可以設置 遞歸鎖 或 非遞歸鎖 。當設置爲 遞歸鎖 時,只有同線程中所有的鎖都被解鎖,其他的線程才能夠獲取該鎖。
關於 遞歸鎖 和 非遞歸鎖 的介紹,可以參照: 線程的互斥和同步(8)- C++11中的互斥鎖和條件變量
同互斥鎖一樣,提供了互斥鎖的管理類: QMutexLocker ;讀寫鎖也提供了,讀鎖和寫鎖的管理類:
QReadLocker 和 QWriteLocker :構造時加鎖,析構時解鎖。這裏就不過多的介紹了。
作者:douzhq
個人博客主頁:不會飛的紙飛機
文章同步頁:線程的互斥和同步(9)- Qt中的讀寫鎖QReadWriteLock