【轉】自旋鎖spin和互斥量mutex的區別

  • 2019 年 10 月 4 日
  • 筆記

在MySQL種,執行show engine innodb status G 經常會看到裏面有spin lock 及mutex的情況。我們有必要了解下這些知識。

自旋鎖(spin lock)與互斥量(mutex)的比較 自旋鎖是一種非阻塞鎖,也就是說,如果某線程需要獲取自旋鎖,但該鎖已經被其他線程佔用時,該線程不會被掛起,而是在不斷的消耗CPU的時間,不停的試圖獲取自旋鎖。 互斥量是阻塞鎖,當某線程無法獲取互斥量時,該線程會被直接掛起,該線程不再消耗CPU時間,當其他線程釋放互斥量後,操作系統會激活那個被掛起的線程,讓其投入運行。 兩種鎖適用於不同場景: 如果是多核處理器,如果預計線程等待鎖的時間很短,短到比線程兩次上下文切換時間要少的情況下,使用自旋鎖是划算的。 如果是多核處理器,如果預計線程等待鎖的時間較長,至少比兩次線程上下文切換的時間要長,建議使用互斥量。 如果是單核處理器,一般建議不要使用自旋鎖。因為,在同一時間只有一個線程是處在運行狀態,那如果運行線程發現無法獲取鎖,只能等待解鎖,但因為自身不掛起,所以那個獲取到鎖的線程沒有辦法進入運行狀態,只能等到運行線程把操作系統分給它的時間片用完,才能有機會被調度。這種情況下使用自旋鎖的代價很高。 如果加鎖的代碼經常被調用,但競爭情況很少發生時,應該優先考慮使用自旋鎖,自旋鎖的開銷比較小,互斥量的開銷較大。 參考文獻 《多核程序設計技術》 《Linux內核設計與實現》 from:http://blog.csdn.NET/swordmanwk/article/details/6819457 pthread與tbb中各種鎖的對比測試 pthread中提供的鎖有:pthread_mutex_t, pthread_spinlock_t, pthread_rwlock_t。 pthread_mutex_t是互斥鎖,同一瞬間只能有一個線程能夠獲取鎖,其他線程在等待獲取鎖的時候會進入休眠狀態。因此pthread_mutex_t消耗的CPU資源很小,但是性能不高,因為會引起線程切換。 pthread_spinlock_t是自旋鎖,同一瞬間也只能有一個線程能夠獲取鎖,不同的是,其他線程在等待獲取鎖的過程中並不進入睡眠狀態,而是在CPU上進入「自旋」等待。自旋鎖的性能很高,但是只適合對很小的代碼段加鎖(或短期持有的鎖),自旋鎖對CPU的佔用相對較高。 pthread_rwlock_t是讀寫鎖,同時可以有多個線程獲得讀鎖,同時只允許有一個線程獲得寫鎖。其他線程在等待鎖的時候同樣會進入睡眠。讀寫鎖在互斥鎖的基礎上,允許多個線程「讀」,在某些場景下能提高性能。 諸如pthread中的pthread_cond_t, pthread_barrier_t, semaphone等,更像是一種同步原語,不屬於單純的鎖。 TBB中提供的鎖有: mutex 互斥鎖,等同於pthread中的互斥鎖(實際上就是對pthread_mutex_t進行封裝) recurisive_mutex 可重入的互斥鎖,在pthread_mutex_t的基礎上加了一個可重入的屬性 spin_metux 自旋鎖,與pthread_spinlock_t類似,但是性能比pthread_spinlock_t低28% queuing_metux 公平的互斥鎖,嚴格按照等待鎖的先後順序獲得鎖 spin_rw_mutex 讀寫自旋鎖,功能與pthread_rwlock_t一致,但是性能比pthread_rwlock_t高很多 queuing_rw_mutex 公平的讀寫讀寫鎖,也是嚴格按照等待鎖的先後順序獲得鎖 以下是我對一個擁有3667527個節點的HASH表進行讀操作所花費的時間,可以說明各種鎖的性能: (多線程的環境為:4CPU的電腦上使用四個線程進行同樣的度操作,然後取四個線程讀取的平均時間) ·單線程不加鎖:0.818845s ·多線程使用pthread_mutex_t:120.978713s   (很離譜吧…………我也嚇了一跳) ·多線程使用pthread_rwlock_t:10.592172s   (多個線程加讀鎖) ·多線程使用pthread_spinlock_t:4.766012s ·多個線程使用tbb::spin_mutex:6.638609s     (從這裡可以看出pthread的自旋鎖比TBB的自旋鎖性能高出28%) ·多個線程使用tbb::spin_rw_mutex:3.471757s (並行讀的環境下,這是所有鎖中性能最高的) OK,有了以上的測試結果,何種環境該使用何種鎖,不辨自明。 from:http://hi.baidu.com/ah__fu/item/5bb98aaaebf5c113a9cfb758 #include <tbb/spin_rw_mutex.h> tbb::spin_rw_mutex g_rwMutex; tbb::spin_rw_mutex::scoped_lock lock(g_rwMutex); #include <boost/thread/mutex.hpp> boost::mutex io_mutex; boost::mutex::scoped_lock lock(io_mutex);