原子操作,自旋鎖,互斥鎖

2020-12-04 閒聊代碼

原子操作(atomic),自旋鎖(spinlock),互斥鎖(mutex),是常用的保護共享數據的方法,用於高並發程序裡的進程線程同步。

自旋鎖和互斥鎖的基礎是原子操作。

1,原子操作,

原子操作,是一條彙編代碼,它會保證CPU對內存的原子訪問,不受其他CPU核(多核處理器)和進程調度的影響。

如果只是實現鎖而不進行複雜運算的話,彙編指令xchg就可以達到效果。

它可以交換一個寄存器與一個內存整數的值,並且保證這種交換不會受到其他CPU核和調度器的幹擾。

volatile int lock = 0;

如果變量lock的指針&lock放在寄存器rdi裡,整數1放在變量eax裡,那麼交換這兩個值就是一個可以實現鎖的原子操作。

xchg %eax,(%rdi)

實際的C內嵌彙編是如下圖這麼寫:

「r」表示寄存器,「m」表示內存,帶「=」表示輸出,不帶表示輸入。

%後的數字編號從左到右、從上到下,以0開始。

變量r放在0號位置可以寫為 「0」(r)。

作為鎖的int變量一定要聲明為volatile,以防編譯器胡亂優化。

傳給xchg函數的一定是指針,只有通過指針修改的才是鎖的變量本身,而不是xchg()函數的形參。

2,自旋鎖和互斥鎖,

在xchg()函數的基礎上實現鎖,就是先把鎖初始化為0,表示沒有加鎖,然後用1去與鎖的值交換:

如果返回的是0,表示鎖之前是開著的,加鎖成功(此時鎖的值為1);

如果返回的是1,表示鎖之前已經鎖住(值為1),加鎖失敗(鎖的值保持不變,還是1)。

所以,spin_lock()可以這麼實現:

void spin_lock(volatile int* p)

{

while (1 == xchg(p))

sched_yield();

}

sched_yield()函數表示放棄CPU,調度其他線程執行,有利於持有鎖的線程儘快處理完數據,釋放鎖。

如果是獲取鎖失敗之後不放棄CPU,而是一直嘗試獲取,那麼另一個持有鎖的線程就不能及時得到執行,降低效率。

這種自旋鎖是用戶態自旋鎖,只用於進程間的同步。

線程間的同步還是使用pthread_mutex,它是基於Linux的futex()系統調用實現的,效率要更高。

futex在獲取鎖失敗之後會進入內核,讓當前線程掛在鎖的等待隊列(wait queue)上休眠。當有其他線程釋放這個鎖時再喚醒它運行,不至於循環調用sched_yield()放棄CPU,效率要更高。

釋放鎖,自然是把鎖的變量賦值為0就行,賦值只需要一條指令,本身就是原子的。

void spin_unlock(volatile int* p)

{

*p = 0;

}

這個相當於mov $0, (%rdi)。

如果是spin_trylock(),則可以直接返回xchg()值並且取反,因為xchg()返回0時加鎖成功,與if的條件true正好反著。

也可以嘗試一定次數(例如1000次)之後再返回結果。

int spin_trylock(volatile int* p)

{

int n = 0;

while(1 == xchg(p)) {

n++;

if (n < 1000)

sched_yield();

else

return 0;

}

return 1;

}

如果是基於futex實現的,則在獲取鎖失敗之後不需要自旋等待,而是進入內核的等待隊列,在其他線程釋放鎖時被喚醒,即通常的互斥鎖pthread_mutex,它在多線程程序裡廣泛使用。

用戶態自旋鎖,在nginx裡用來做多進程worker之間的負載均衡,讓負載最低的worker進程去監聽用戶接入的socket並執行accept,而不是所有的worker都去監聽。

否則,在新用戶接入時會導致epoll的驚群,即所有worker都被喚醒,但只有一個的accept會成功,其他全跑了空循環。

因為監聽的socket也是進程間的共享資源,所以要用鎖去保護它,避免並發訪問。

3,內核自旋鎖,

Linux內核中的高並發異步運行要比用戶態程序複雜的多,而且內核裡不能隨便休眠,也不能隨便調度,所以在保護共享數據時大量使用spinlock自旋鎖。

內核的運行上下文分為:進程(含線程)上下文,中斷上下文,軟中斷上下文。

只有在進程上下文時才可以使用調度器schedule()函數放棄CPU,切換進程。

中斷和軟中斷上下文,是不能放棄CPU的,否則執行路徑會被打亂。

進程上下文包括:進程,線程,內核線程,工作隊列。

軟中斷和tasklete都是軟中斷上下文,網絡數據的收發都是通過軟中斷softirq處理的。

鍵盤、滑鼠、時鐘、網卡之類的都是中斷,中斷服務例程irq只處理最緊急的工作,這是中斷上下文,也叫中斷的頂半部。

不太緊急的工作放到底半部,可以用軟中斷、tasklete、內核線程、工作隊列處理。

不展開了:(

最後,鎖要保護數據,不是保護代碼。

相關焦點

  • C++11原子類型如何使用?答案在這裡,請查收
    而C++11提供了原子類型,這很大程度上簡化程式設計師對並發操作的難度。本文首先從posix標準的pthread庫提供的互斥鎖開始介紹早期控制多線程並發的操作方式, 接著再重點說明C++11提供的內置原子類型以及模版原子類型的用法,最後再簡單介紹幾個內存模型的含義。
  • 價層電子對互斥理論要點解析
    1、價層電子對互斥理論要點:價層電子對儘可能遠離以減小斥力,並使分子或離子儘可能採取對稱的立體構型。2、價層電子對理論的應用:判斷分子或離子的立體構型。有1個中心原子的分子、離子或原子團的立體構型。價層電子對理論只能判斷1個中心原子的分子、離子或原子團的立體構型,所謂一個中心,就是在分子中,多個原子都以共價鍵連在一個原子上,如H-O-H中的氧就是中心原子。但該理論不能判斷出多中心的分子或離子的立體構型。如H-O-O-H,有兩個中心原子, CH2=CH-CH2-CH3有四個中心原子。
  • 《價層電子對互斥理論1》微課!
    看了本節微課,你會對價層電子對互斥理論有更深一步的理解
  • 互斥不獨立,獨立不互斥,對嗎?
    微信暱稱為「依凡」的讀者朋友,是公眾號的鐵桿粉絲了.她問到下面這樣一個問題:兩個事件A,B,互斥一定不獨立,獨立一定不互斥
  • 多線程面試和進階必備-任務同步最常用的十種鎖的原理
    要避免該問題,可以鎖定共享對象,鎖定共享對象就要加鎖,這也是今天要分享的鎖機制。但是過多的鎖,會導致另外一個問題,那就是死鎖。這時至少有兩個線程被掛起,並且等待對方解除鎖定。由於兩個線程都在等待對方,因此就出現了死鎖,線程將無限等待下去。本文針對上述兩個問題,和大家分享下十種常用的鎖。
  • 互斥與對立
    互斥事件與對立事件是兩個容易混淆的概念。錄製了一個小視頻,還有兩道檢測題,後面有答案,自測一下。.(2018河南安陽聯考,3)從1,2,3,6這4個數中一次隨機地取2個數,記所取的這2個數的乘積為m,則下列說法錯誤的是()A.事件「m=6」的概率為B.事件「m>2」的概率為C.事件「m=2」與事件「m=6」為互斥事件D.事件「m=2」與事件「m>2」互為對立事件停 下面答案
  • 共軛Π鍵、配位鍵和價層電子對互斥理論
    另外,今天如果不發,我怕明天事情更多,趁周末只有操作考試,周末還是發一些考研題,不然對不住考研的黨的關注。我們學習雜化軌道時,重在討論了雜化軌道的類型,雜化軌道的空間構型,以及軌道的成鍵情況。而我們舉的所有的例子,都剛好巧,所有的價電子所佔據軌道都參與了雜化。
  • 圖解golang裡面的讀寫鎖實現與核心原理分析了解程式語言背後設計
    基礎築基1.1 讀寫鎖的特點讀寫鎖區別與互斥鎖的主要區別就是讀鎖之間是共享的,多個goroutine可以同時加讀鎖,但是寫鎖與寫鎖、寫鎖與讀鎖之間則是互斥的1.2 寫鎖飢餓問題因為讀鎖是共享的,所以如果當前已經有讀鎖,那後續goroutine繼續加讀鎖正常情況下是可以加鎖成功,但是如果一直有讀鎖進行加鎖,那嘗試加寫鎖的goroutine則可能會長期獲取不到鎖
  • 高三數學辨析專題---概率模型中互斥、對立、獨立事件
    在學習排列、組合和概率的學習過程中,不少同學對概率中的互斥、對立、獨立事件等概念混淆不清,不能準確理解這些概念的本質內涵,導致不能熟練掌握互斥事件的概率加法公式與相互獨立事件的概率乘法公式計算一些事件的概率。因此下面談一談這些概念間的區別和聯繫,以期對同學們的學習有所幫助。
  • 2020年安徽教師招聘化學筆試之 價層電子對互斥理論
    價層電子對互斥理論(教綜19天速學班1.1元於10月20日開課)教師招聘考試中,選修三的知識內容也會有所涉及,價層電子對互斥理論就是其中的常考考點。價層電子對互斥理論常常結合物質的空間構型和雜化方式出題,一般以選擇或填空的形式考查,難度適中。
  • 火焰原子吸收分光光度計日常維護操作
    火焰原子吸收分光光度計的日常維護的對象包括:空心陰極燈、火焰原子化器。這裡火焰原子化器作為原子吸收分光光度計日常維護的重點,我們將火焰原子化器維護工作又細分為:霧化室維護,霧化器維護,燃燒器維護。下面,聚創環保將分別介紹:1.空心陰極燈的維護如果我們的原子吸收分光光度計在長期擱置不用的情況下,儀器的空心陰極燈就會出現不同程度的損傷,比如會出現氣體吸附和漏氣的現象,從而造成原子吸收分光光度計的使用故障,會導致在檢測前儀器不能被點燃的現象
  • 原子中子粒子這麼小,科學家們是怎麼操作並利用它們的呢?
    一、生活中如何處理微觀粒子1、原子、分子這樣的小東西,其實我們無時無刻都在接觸之中。我們的身體就是一個巨大的化工廠,我們把食物分解成可以吸收的糖、胺基酸等分子,然後被身體吸收。或者釋放身體儲存的糖分,讓它們氧化釋放能量,提供對生命活動的支持。這些都是在原子分子級別的化學反應。2、在生產實踐中,大量的食品加工和化工生產,其實都是原子分子一級的操作。
  • 中科大33歲教授再發《自然》:實現原子與分子間的量子糾纏
    在雷射控制下,被困在電磁場陷阱中的一個分子離子和一個原子離子出現了神奇的糾纏效應。5月20日,發表在世界頂級學術期刊《自然》上的一篇論文報告了這種在分子層面上的量子控制能力。而光子和原子之間會發生相互作用,原子吸收或失去光子後能級會升高或降低,可以利用這種相互作用使得光子和原子糾纏起來,甚至通過一個光子的連續相互作用將多個原子糾纏起來。在實際操作中,要對原子實現如此精確的操控和測量,關鍵還是把原子固定住,減少它的振動。
  • 可以讓你甩掉笨重鑰匙的U型鎖-易鎖寶智能藍牙U型鎖
    在生活中我們會遇到很多因為鎖帶來的不便。今天神瞰君拿到易鎖寶智能藍牙U型鎖,它會幫你解決這一系列的問題。這款鎖可以通過微信小程序一鍵藍牙解鎖。遠程授權並可以控制授權時間的長短,同時可以隨時查詢開鎖記錄。
  • 指紋鎖開不了門怎麼辦 指紋鎖有哪些常見的選購標準
    指紋鎖是非常常見的防盜產品,而且已經非常普遍,適用於各種不同的家庭環境,大家如果也想要安裝這些門鎖,可以看看各種優質的品牌。當然也有一些人遇到開不了鎖的情況,這時要分析指紋鎖開不了門怎麼辦,找到優質的品牌,了解清楚指紋鎖有哪些常見的選購標準,重新進行更換。