天天看點

spin_lock 自旋鎖互斥鎖、讀寫鎖和自旋鎖的差別:

自旋鎖 Spin lock 的實作是為了保護一段短小的臨界區操作代碼,保證這個臨界區的操作是原子的,進而避免并發的競争冒險。在Linux核心中,自旋鎖通常用于包含核心資料結構的操作,你可以看到在許多核心資料結構中都嵌入有spinlock,這些大部分就是用于保證它自身被操作的原子性,在操作這樣的結構體時都經曆這樣的過程:上鎖->操作->解鎖。

如果核心控制路徑發現自旋鎖“開着”(可以擷取),就擷取鎖并繼續自己的執行。相反,如果核心控制路徑發現鎖由運作在另一個CPU上的核心控制路徑“鎖着”,就在原地“旋轉”,反複執行一條緊湊的循環檢測指令,直到鎖被釋放。 自旋鎖是循環檢測“忙等”,即等待時核心無事可做(除了浪費時間),程序在CPU上保持運作,是以它保護的臨界區必須小,且操作過程必須短。不過,自旋鎖通常非常友善,因為很多核心資源隻鎖1毫秒的時間片段,是以等待自旋鎖的釋放不會消耗太多CPU的時間。

自旋鎖需要阻止在代碼運作過程中出現的任何并發幹擾。這些“幹擾”包括: 中斷,包括硬體中斷和軟體中斷 (僅在中斷代碼可能通路臨界區時需要)、核心搶占(僅存在于可搶占核心中)、其他處理器對同一臨界區的通路 (僅SMP系統)。spin lock需要在晶片底層實作實體上的記憶體位址獨占通路,并且在實作上使用特殊的彙編指令通路

以arm為例,從存在SMP的ARM構架指令集開始(V6、V7),采用LDREX和STREX指令實作真正的自旋等待。

https://blog.csdn.net/electrombile/article/details/51289813  linux_spinlock_實作機制

http://blog.chinaunix.net/uid-20543672-id-3252604.html 深入分析Linux自旋鎖

https://www.cnblogs.com/alantu2018/p/8447497.html     Linux核心同步 - spin_lock

--------------------------------------------------------------------------------------------------------------

互斥鎖、讀寫鎖和自旋鎖的差別:

從 實作原理上來講,Mutex屬于sleep-waiting類型的鎖。例如在一個雙核的機器上有兩個線程(線程A和線程B),它們分别運作在Core0和 Core1上。假設線程A想要通過pthread_mutex_lock操作去得到一個臨界區的鎖,而此時這個鎖正被線程B所持有,那麼線程A就會被阻塞 (blocking),Core0 會在此時進行上下文切換(Context Switch)将線程A置于等待隊列中,此時Core0就可以運作其他的任務(例如另一個線程C)而不必進行忙等待。 一次隻能一個線程擁有互斥鎖,其他線程隻有等待。

Spin lock則不然,它屬于busy-waiting類型的鎖,如果線程A是使用pthread_spin_lock操作去請求鎖,那麼線程A就會一直在 Core0上進行忙等待并不停的進行鎖請求,直到得到這個鎖為止。 自旋鎖不會引起調用者睡眠,如果自旋鎖已經被别的執行單元保持,調用者就一直循環在那裡看是 否該自旋鎖的保持者已經釋放了鎖。

自旋鎖的效率遠 高于互斥鎖。雖然它的效率比互斥鎖高,但是它也有些不足之處:

    1、自旋鎖一直占用CPU,在未獲得鎖的情況下,一直運作-----自旋,是以占用着CPU,如果不能在很短的時 間内獲得鎖,這無疑會使CPU效率降低。

    2、在用自旋鎖時有可能造成死鎖,當遞歸調用時有可能造成死鎖,調用有些其他函數也可能造成死鎖,如 copy_to_user()、copy_from_user()、kmalloc()等。

TIP:

  • 自旋鎖隻有在核心可搶占式或SMP的情況下才真正需要,在單CPU且不可搶占式的核心下,自旋鎖的操作為空操作。自旋鎖适用于鎖使用者保持鎖時間比較短的情況下。

讀寫鎖有三種狀态:讀加鎖狀态、寫加鎖狀态和不加鎖狀态。

隻有一個線程可以占有寫狀态的鎖,但可以有多個線程同時占有讀狀态鎖,這也是它可以實作高并發的原因。

  • 當其處于寫狀态鎖下,任何想要嘗試獲得鎖的線程都會被阻塞,直到寫狀态鎖被釋放;
  • 如果是處于讀狀态鎖下,允許其它線程獲得它的讀狀态鎖,但是不允許獲得它的寫狀态鎖,直到所有線程的讀狀态鎖被釋放;
  • 為了避免想要嘗試寫操作的線程一直得不到寫狀态鎖,當處于讀模式的讀寫鎖接收到一個試圖對其進行寫模式加鎖操作時,便會阻塞後面對其進行讀模式加鎖操作的線程。 即當讀寫鎖感覺到有線程想要獲得寫狀态鎖時,便會阻塞其後所有想要獲得讀狀态鎖的線程。

        【如果預感有寫的期望,那麼後續的讀加鎖将不被受理。】

1)多個讀者可以同時進行讀

2)寫者必須互斥(隻允許一個寫者寫,也不能讀者寫者同時進行)

3)寫者優先于讀者(一旦有寫者,則後續讀者必須等待,喚醒時優先考慮寫者)

RCU鎖(Read-Copy Update)

RCU中,讀者不需要使用鎖,要通路資源盡管通路就好了。

RCU中,寫者的同步開銷比較大,要等到所有的讀者都通路完成了才能夠對被保護的資源進行更新。

寫者修改資料前首先拷貝一個被修改元素的副本,然後在副本上進行修改,修改完畢後它向垃圾回收器注冊一個回調函數以便在适當的時機執行真正的修改操作。讀者必須提供一個信号給寫者以便寫者能夠确定資料可以被安全地釋放或修改的時機。有一個專門的垃圾收集器來探測讀者的信号,一旦所有的讀者都已經發送信号告知它們都不在使用被RCU保護的資料結構,垃圾收集器就調用回調函數完成最後的資料釋放或修改操作。

繼續閱讀