簡體   English   中英

為什么沒有像 pthread_mutex_t & std::mutex 那樣等同於 pthread_spinlock_t 的 std::?

[英]Why is there no std:: equivalent to pthread_spinlock_t like there is for pthread_mutex_t & std::mutex?

我在並發程序中使用了 pthreads,主要是利用自旋鎖、互斥鎖和條件變量。

我開始使用 std::thread 和 std::mutex 研究多線程,我注意到 pthreads 中似乎沒有與自旋鎖等效的東西。

有誰知道這是為什么?

pthreads 中似乎沒有與自旋鎖等效的東西。

自旋鎖通常被認為是用戶空間中的錯誤工具,因為在持有自旋鎖時無法禁用線程搶占(與內核不同)。 這樣一個線程可以獲取自旋鎖然后被搶占,導致所有其他試圖獲取自旋鎖的線程不必要地自旋(如果這些線程具有更高的優先級,可能會導致死鎖(等待 I/O 的線程可能會獲得優先級)喚醒時提升))。 這種推理也適用於所有無鎖數據結構,除非該數據結構是真正免等待的(除了boost::spsc_queue之外,沒有多少實際有用的結構)。

在 kernel 中,已鎖定自旋鎖的線程在釋放自旋鎖之前不能被搶占或中斷。 這就是為什么自旋鎖在那里是合適的(當不能使用RCU時)。

在 Linux 上,可以通過使用隔離的 CPU 內核和固定到這些隔離內核的 FIFO 實時線程來防止搶占(不確定是否完全,但最近 kernel 朝着這種理想的效果發生了變化)。 但這需要經過深思熟慮的內核/機器配置和旨在利用該配置的應用程序。 盡管如此,人們確實將這種設置用於關鍵業務應用程序以及用戶空間中的無鎖(但不是免等待)數據結構。


在 Linux 上,有自適應互斥鎖PTHREAD_MUTEX_ADAPTIVE_NP ,它在 kernel 中阻塞之前旋轉有限次數的迭代(類似於InitializeCriticalSectionAndSpinCount )。 但是,該互斥鎖不能通過std::mutex接口使用,因為在初始化pthread_mutex_t之前沒有自定義不可移植pthread_mutexattr_t的選項。

既不能通過std::mutex接口啟用進程共享、魯棒性、錯誤檢查或優先級反轉預防。 在實踐中,人們編寫自己的pthread_mutex_t包裝器,允許設置所需的互斥體屬性; 以及相應的條件變量包裝器。 可以重用std::unique_lockstd::lock_guard等標准鎖。

IMO,可以規定在std:: API 中設置所需的互斥鎖和條件變量屬性,例如為派生類提供一個protected的構造函數,該構造函數將初始化該native_handle ,但沒有。 那個native_handle看起來是做平台特定的東西的好主意,但是,必須有一個派生的 class 的構造函數才能適當地初始化它。 在初始化互斥鎖或條件變量后, native_handle幾乎沒有用。 除非這個想法只是為了能夠將該native_handle傳遞給(C 語言)API,這些 API 需要一個指針或對已初始化pthread_mutex_t的引用。


還有一個 Boost/C++ 標准不接受信號量的例子,因為信號量太大而無法自拔,互斥量(本質上是二進制信號量)和條件變量是更基本、更靈活的同步原語,out其中可以建立一個信號量

從 C++ 標准的角度來看,這些可能是正確的決定,因為教育用戶正確使用所有細微差別的自旋鎖和信號量是一項艱巨的任務。 而高級用戶可以毫不費力地為pthread_spinlock_t制作一個包裝器

你是對的,std 命名空間中沒有自旋鎖實現。 自旋鎖是一個很棒的概念,但在用戶空間中通常很差。 操作系統不知道您的進程想要旋轉,通常您會得到比使用互斥鎖更糟糕的結果。 需要注意的是,在幾個平台上實現了樂觀旋轉,因此互斥鎖可以做得很好。 此外,調整每個循環迭代之間的“暫停”時間並非易事且可移植,並且需要進行微調。 TL;DR 不要在用戶空間中使用自旋鎖,除非你真的很確定你在做什么。

C++ 線程討論

解釋如何使用基准編寫自旋鎖的文章

Linus Torvalds 對上述文章的回復解釋了為什么這是一個壞主意

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM