背景:
在多線程程式設計中經常面臨這樣一個問題,同一個資料可以被多個線程同時讀取,但是同一時間隻能有一個線程對共享變量進行寫操作。
對該問題常用的解決方法時聲明一個鎖(互斥量)來對共享變量進行保護,這樣每次隻能有一個線程來對資料進行讀寫,會導緻讀取的效率低下。
讀寫鎖:
讀寫鎖算法主要實作對共享資源通路時,可以在多個線程間同時進行讀操作,但是在同一時間内隻能有一個線程對共享資源進行修改,并且在寫操作時不能有線程進行讀操作。
算法思想:
當進行讀操作時不能進行寫操作,是以當有讀操作時需要一把鎖來鎖住寫操作,由于允許多個線程同時讀操作,是以還需要一個變量(count)來記錄目前讀操作的線程個數,由于對count的修改需要互斥,是以還需要一個鎖用來儲存count的修改。
讀寫鎖的資料結構:
typedef struct RWLOCK_st
{
LOCK m_lReadLock;
LOCK m_lWriteLock;
int m_icount;
} RWLOCK;
讀寫鎖操作僞代碼:
1. 聲明一個全局的鎖 RWLOCK rwLock;
rwLock.m_icount = 0;
//讀操作時加鎖
RWLock_LockRead()
{
rwLock.m_lReadLock->lock()
rwLock.m_icount++;
if (rwLock.m_icount == 1)
{
rwLock.m_lWriteLock->lock(); //鎖住寫操作,當有讀操作時隻鎖一次
}
rwLock.m_lReadLock->unlock()
}
RWLock_ReleaseRead()
{
rwLock.m_lReadLock->lock()
rwLock.m_icount--;
if (rwLock.m_icount == 0)
{
rwLock.m_lWriteLock->unlock(); //允許寫操作
}
rwLock.m_lReadLock->unlock()
}
RWLock_LockWrite()
{
rwLock.m_lWriteLock->lock() //鎖住寫操作
}
RWLock_ReleaseWrite()
{
rwLock.m_lWriteLock->unlock()
}
從 RWLock_LockWrite() 和RWLock_ReleaseWrite()中可以看出當進行寫操作時如果有讀操作會阻塞在RWLock_ReleaseRead()函數rwLock.m_lWriteLock->lock()處,當一個線程完成寫操作後,讀操作會和寫操作線程競争rwLock.m_lWriteLock->lock()。
讀寫鎖缺點:
優點上面已經說過。
1. 進行讀操作時會進行再次加鎖和解鎖操作,計算開銷比較大,是以對鎖内計算比較小的操作不适合使用讀寫鎖。
2. 如果讀操作比較密集,使得rwLock.m_icount永遠不可能為0,是以會使寫操作線程餓死。
參考:《多核計算與程式設計》,周偉明