pthread_mutex_lock
通常具有使用原子操作嘗試獲取鎖的快速路徑。如果鎖沒有,這可能非常快。只有當鎖已經被鎖定,線程纔會通過系統調用進入內核。內核獲取一個自旋鎖,然後重新嘗試獲取互斥鎖,以防第一次嘗試釋放該互斥鎖。如果此嘗試失敗,則將調用線程添加到與該互斥鎖關聯的等待隊列中,並執行上下文切換。內核還在互斥體中設置了一些位,以表明有一個等待線程。
pthread_mutex_unlock
也有一個快速路徑。如果等待的線程標誌清除,它可以簡單地釋放鎖。如果該標誌被設置,線程必須通過系統調用進入內核,這樣等待的線程才能被喚醒。同樣,內核必須獲得自旋鎖,以便它可以操縱其線程控制數據結構。如果沒有線程在等待,鎖可以由內核釋放。如果有一個線程在等待,它就會運行,並且互斥量的所有權被轉移而不被釋放。
這個小舞蹈中有許多微妙的競賽條件,希望它能正常工作。
由於嘗試獲取鎖定互斥鎖的線程已切換到上下文環境,因此它不會阻止擁有互斥鎖的線程運行,從而使所有者有機會退出它的臨界區並釋放互斥鎖。
相比之下,嘗試獲取鎖定自旋鎖的線程只是旋轉,消耗CPU週期。這有可能阻止擁有旋轉鎖的線程退出其臨界區並釋放鎖。旋轉的線程在其時間片已被佔用時可被搶佔,從而允許擁有該鎖的線程最終重新獲得控制權。當然,這對於性能並不好。
實際上,使用自旋鎖的地方不會在擁有鎖的情況下搶佔線程。內核可以設置一個per-cpu標誌來防止它從中斷服務程序執行上下文切換(或者它可以提高中斷優先級以防止可能導致上下文切換的中斷,或者它可能完全禁止中斷)。用戶線程可以通過提高優先級來阻止自己被搶佔(由同一進程中的其他線程搶佔)。請注意,在單處理器系統中,防止當前線程被搶佔,從而不需要旋轉鎖定。或者,在多處理器系統中,可以將線程綁定到cpus(cpu affinity),以便它們不會搶佔彼此。所有的鎖最終都需要一個原子基元(很好,高效的鎖;參見here的一個反例)。如果互斥體高度競爭,互斥鎖可能效率低下,導致線程不斷進入內核並進行上下文切換;特別是如果臨界區小於內核開銷。自旋鎖可以更有效率,但只有當擁有者不能被搶佔並且關鍵部分很短時。請注意,當線程嘗試獲取鎖定的互斥鎖時,內核仍然必須獲取旋轉鎖定。
就我個人而言,我會使用原子操作來處理共享計數器更新和互斥鎖等更復雜的操作。只有在分析之後,我纔會考慮用自旋鎖代替互斥體(並找出如何處理搶佔)。請注意,如果您打算使用condvars,則別無選擇,只能使用互斥鎖。
來源
2014-03-14 06:14:12
pat
'pthread_spin_lock'最可能是用原子操作實現的,你想實現什麼?如果你想在關鍵部分執行*的內容只是更新/增量或類似的東西,你肯定應該使用原子構建(或C11'_Atomic')來執行操作並根本不鎖定。 –
我想用pthread_spin_lock鎖定關鍵部分。根據我插入的URL,看起來存在其他線程無限期旋轉的風險。我的問題是,如果我通過使用compare_and_swap + atomic來執行關鍵區域的鎖定,會發生什麼情況...是否有其他線程可能因搶佔而無限期旋轉? –
@Jens:我再補充一些解釋。我需要鎖定一小段關鍵部分。 –