如何快速又正確地在C++裡實現鎖

工程師WWW發表於2016-05-23

正確答案是 不要自己實現 。

從C++11開始,STL已經提供了multithreading相關的設施,包括鎖這種基本的同步設施;如果很不幸的,你的生產環境被三體人鎖在了C++98/03,那麼你可以考慮使用boost。這個看起來亂糟糟的準標準庫也提供了相關的同步設施,而且用起來的體驗還和C++11的標準庫非常相像。

當然,如果文章到這裡就結束的話,不免有些標題黨之嫌。所以,我們還是要討論一下正題:如果你不能使用新標準,並且不想背上boost這樣一個大包袱(例如一個寫給自己的小工具),那麼考慮自己實現一個鎖也在情理之中。

然而在動手之前,有幾個問題一定要想清楚,否則免不了蛋疼菊緊。

Point 0: 選好巨人的腦袋

鎖作為基本的同步設施,除非你要自己寫一個作業系統,否則是沒有可能讓你從無到有擼一個出來的。

所以首先要做的是確定你要踩在誰的腦袋上:在Windows上,你需要的是CRITICAL_SECTION 以及相關的API;在Linxu上,或者說支援POSIX標準的平臺上,你需要的是 pthread_mutex 。

需要注意的是,Windows上的 CRITICAL_SECTION 是可重入鎖(reentrant-lock),而 pthread_mutex 是不可重入的。

雖然目前工業界偏向於 可重入鎖是非必需且危險的 ,是否提供可重入性以及是否預設提供重入性還是需要你自己考慮。

另外,如果你覺得需要自己實現一個pthread,那我只能說: 有什麼心事和爸爸說,爸爸愛你 。

最後,上述兩樣都是執行緒間的輕量鎖,如果你真的需要程式間的全域性鎖,確認自己的需求無誤後替換相應的底層設施即可…

Point 1: 你需要一個 Mutex class,一個 Lock class

要在C++里正確的實現鎖機制,你一定需要將鎖分成兩部分,因為只有這樣才能正確實現RAII。

通常來說,也就是需要將鎖拆分成描述臨界區的類(自己可以帶鎖操作),和描述上鎖/解鎖動作的類。

這麼做還有另外一個附加的好處:不經意間做到了 策略與機制分離 

對於C++11或者Boost,他們提供了各種mutex,例如最基本的 mutex ,代表可重入的 recursive_mutex ,支援超時的 timed_mutex .etc 這部分代表了 what the lock can do 。

類似的,描述鎖動作的類有 lock_guard 和 unique_lock ,他們代表了 how exactly the lock would do 。

Point 2: 夠用就行,過猶不及

看完point 1你沒準也想自己實現一整套完善的鎖設施,但是不要這麼做。

先不考慮可操作性,你有這閒情去實現一套完備的boost-ex,還不如考慮把程式碼遷移到C++11的環境上或者直接使用boost,把多出來的時間用來把妹。

總之,don’t lose your target。

Implementation in Action

明白上面說的三點後,就可以動手實現了。

啪啪啪啪啪…啪啪啪啪啪…

不過最後我不打算提供一個自己實現的版本,因為我壓根不會自己去實現。

但是為了避免你們看到這裡罵街,我打算貼一個已經用在工業產品上的實現,也就是 chromium-base-lock (可能需要梯子)

  • 一個代表 mutex 的 LockImpl 。不過因為需要跨平臺,所以在這一層做了一個抽象,下面有針對windows和linux的具體impl。同樣建立在 CRITICAL_SECTION 和pthread 之上。
  • 一個代表 lock 的 Lock (conditional variable需要能夠支援手動鎖操作的lock),以及為了實現RAII的 AutoLock / AutoUnlock

這個實現完全符合我上面說的那幾點,而且足夠輕量,你就是要抄起來也非常快。

相關文章