Introduction to C++ multithread Part 4-2
January 02, 2017打鐵要趁熱 來看multithread第二常見的example
Read/Write Lock
How to make a multiple-read/single-write lock
老話一句 跑起來加速理解
main裡面initiliza一個rw lock 把他丟給所有的thread 注意這裡要用reference丟 這樣所有thread才會用到同一個rw lock
func也簡單 就是要改動result前call WriteLock 改完後call WriteUnlock
Read/Write Lock Deep dive
RWLock這個data structure裡面有一個共用的mutex 跟兩個condition variable readerQ跟writerQ
active_readers, waiting_writers, active_writers 是紀錄現在的state的變數
基本上就是4個function
- ReadLock
- ReadUnlock
- WriteLock
- WriteUnlock
ReadLock:
1.Acquire lock
2.確認condition 不該做事的話就進CV wait 該做事就往下走 這裏的寫法只是比較fancy一點 但下列這兩個寫法是等價的
第一個寫法是我Part4-1的寫法 對初學者比較好懂 但要用第二個寫法的話 就把那個function解讀成wait until f 雖然比較難理解但第二個寫法漂亮一些 就可以把判斷要不要做事的logic寫在另一個function而不是全部塞進while的condition
至於bind和this是什麼意思 有興趣可以詳讀這篇文章 淺談C++ bind function 在這裏先把它看成
3.所以ReadLock要做事的condition 就是沒人在寫或是有人在讀 這個情況下就可以安心進去讀
4.把active_reader++
5.解鎖(optional)
ReadUnLock:
1.Acquire lock
2.改變shared data
3.解鎖(optional)
4.去叫writer thread queue的一個writer thread起床
WriteLock:
1.Acquire lock
2.讓自己先去等waiting_writer++;
3.確認condition 不該做事的話就進CV wait 該做事就往下走 這裏的condition是沒有人讀而且沒有人寫 那我就可以安心write
4.--waiting_writers, ++active_writers, 讓所有人知道有人在寫
5.解鎖(optional)
WriteUnLock:
1.Acquire lock
2.改變shared data
3.確認現在的state 如果有writer再等 叫一個writer起床 如果沒有人在等 去叫reader thread queue的所有reader thread起床 因為我們默許 多個reader可以同時read 所以就是個部隊起床的概念
4.解鎖(optional)
講解到這邊 我還寫了個不安全的版本 只要把main裡面的第一個for loop改一下thread call的function就可以
打完收工 問問題時間 如果你夠認真的話 你應該會有兩個問題
Q1. 為什麼ReadUnlock的時候是先解鎖再notify 但WriteUnlock是先notify在解鎖呢
A1. 好問題 因為WriterUnLock在判斷要notify誰的時候 需要access shared data, 所以不能把鎖放掉
Q2. 既然你reader拿鎖的條件 其中一個是active_reader > 0, 那如果reader thread很多的話 很有可能active_reader會一直不為0 writer可能永遠拿不到鎖怎麼辦
A2. Perfect question! 如果你沒念過read/write lock但卻能自己想到這問題 那代表說你極為聰明
本篇文章的實作是Read-preferring的RW Lock 每當有新的reader進來 他發現有人在read 那他也跟著read 都不管writer受得了受不了
所以可能writer會starve
那Write-preferring的RW Lock怎麼改呢 很簡單 就改變reader做事的condition即可
這樣reader就會等到沒有人寫也沒有人等著寫的時候 才會read 只要有writer來 writer之後的reader都要等
當然你可以定義自己的application想怎麼玩 你也可以在WriterUnlock的時候先判斷有沒有waiting_readers 有的話先notify_readerQ 或是你可以限定最多同時有多少個reader在read 隨便你愛怎麼玩就怎麼玩 只是可能需要更多variable記錄現在的state 然後記得要更動這些state variable的時候鎖要拿著就好了
恭喜你已經通透了multi-thread最難的部分 相信之後不論是任何語言的multi-thread問題你都能快速上手