如何快速又正確地在C++裡實現鎖
正確答案是 不要自己實現 。
從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
這個實現完全符合我上面說的那幾點,而且足夠輕量,你就是要抄起來也非常快。
相關文章
- Redis分散式鎖的正確實現方式Redis分散式
- 分散式鎖實現的正確開啟方式分散式
- 這才是實現分散式鎖的正確姿勢!分散式
- 「分散式」實現分散式鎖的正確姿勢?!分散式
- Java 如何正確地輸出日誌Java
- 如何正確地寫出單例模式單例模式
- Android-如何正確地使用HandlerAndroid
- 在iOS中如何正確的實現行間距與行高iOS
- 如何正確實現 Java 中的 HashCodeJava
- 如何實現在H5裡調起高德地圖APP?(下)H5地圖APP
- 如何實現在H5裡調起高德地圖APP?(上)H5地圖APP
- redis應用系列一:分散式鎖正確實現姿勢Redis分散式
- 正確的equals實現
- 在Golang中如何正確地使用database/sql包訪問資料庫GolangDatabaseSQL資料庫
- 如何正確實現Java中的hashCode方法Java
- 解鎖 Redis 鎖的正確姿勢Redis
- 解鎖redis鎖的正確姿勢Redis
- 正確實現 IDisposable------
- 在 Laravel Mix 裡使用 Vux 2 的正確姿勢LaravelUX
- 如何快速自建Git服務,實現異地同步?Git
- 在PPt中快速準確地選擇多個物件物件
- 如何正確地實現Java模組與inter-module Maven構建測試依賴關係JavaMaven
- 【譯】如何通過 INUIAddVoiceShortcutButtonDelegate 正確地使用 INUIAddVoiceShortcutButtonUI
- 如何實現一個地相簿封裝,可以快速切換地圖封裝地圖
- 正確的折半查詢實現
- DevOps如何正確的在企業內進行實踐dev
- Redis 分散式鎖的正確實現原理演化歷程與 Redission 實戰總結Redis分散式
- Swift 里正確地 addTarget(_:action:for:)Swift
- 如何在word裡實現在方框中打勾
- 有效地在 PBootCMS 中呼叫站點資訊,並確保頁面顯示正確boot
- 怎麼自己製作地圖?如何快速實現簡單地圖繪製?地圖
- NSACE|如何正確地維護企業的網路資訊保安?
- 如何正確地使用Python的屬性和描述符Python
- 多方位全面解析:如何正確地寫好一個介面
- 讀《原則》(一):“正確地失敗”
- C++ 實現Golang裡的deferC++Golang
- 如何正確部署 QUICUI
- 如何實現 mysql 匯出資料,驗證頁面正確性?MySql