GO 互斥鎖sync.Mutex (1)

在去學(xué)習(xí)go語(yǔ)言鎖機(jī)制的時(shí)候讶舰,我會(huì)問(wèn)自己幾個(gè)問(wèn)題:

1.鎖是什么 鞍盗,為什么要用鎖需了?
2.都有哪些鎖怎么用?
3.出現(xiàn)問(wèn)題了怎么辦般甲?
4.如何抉擇和調(diào)優(yōu)肋乍?

鎖是什么 ,為什么要用鎖敷存?

在解釋什么是鎖之前墓造,我們先了解下什么樣的場(chǎng)景需要使用到鎖,鎖用于解決什么問(wèn)題锚烦。
Go 語(yǔ)言宣揚(yáng)的“用通訊的方式共享數(shù)據(jù)”,用句白話說(shuō)就是可以用channel來(lái)實(shí)現(xiàn)鎖的功能.但是通過(guò)共享數(shù)據(jù)的方式來(lái)傳遞信息和協(xié)調(diào)線程運(yùn)行的做法其實(shí)更加主流觅闽。go依然提供了很多傳統(tǒng)的并發(fā)控制api,這些東西基本都在sync包中涮俄。

競(jìng)態(tài)條件

用共享數(shù)據(jù)的方式來(lái)傳遞信息勢(shì)必會(huì)面臨一個(gè)問(wèn)題蛉拙,一旦數(shù)據(jù)被多個(gè)線程共享,那么就很可能會(huì)產(chǎn)生爭(zhēng)用和沖突的情況彻亲。這種情況也被稱為競(jìng)態(tài)條件(race condition)孕锄。

數(shù)據(jù)的一致性

競(jìng)態(tài)條件往往會(huì)破會(huì)共享數(shù)據(jù)的一致性。
共享數(shù)據(jù)的一致性代表著某種約定苞尝,即:多個(gè)線程對(duì)共享數(shù)據(jù)的操作總是可以達(dá)到它們各自預(yù)期的效果畸肆。
如果這個(gè)一致性得不到保證,那么將會(huì)影響到一些線程中代碼和流程的正確執(zhí)行宙址,甚至?xí)斐赡撤N不可預(yù)知的錯(cuò)誤轴脐。這種錯(cuò)誤一般都很難發(fā)現(xiàn)和定位,排查起來(lái)的成本也是非常高的抡砂,所以一定要盡量避免大咱。

例子:

舉個(gè)例子,同時(shí)有多個(gè)線程連續(xù)向同一個(gè)緩沖區(qū)寫(xiě)入數(shù)據(jù)塊舀患,如果沒(méi)有一個(gè)機(jī)制去協(xié)調(diào)這些線程的寫(xiě)入操作的話徽级,那么被寫(xiě)入的數(shù)據(jù)塊就很可能會(huì)出現(xiàn)錯(cuò)亂。比如聊浅,在線程A還沒(méi)有寫(xiě)完一個(gè)數(shù)據(jù)塊的時(shí)候餐抢,線程B就開(kāi)始寫(xiě)入另外一個(gè)數(shù)據(jù)塊了。顯然低匙,這兩個(gè)數(shù)據(jù)塊中的數(shù)據(jù)會(huì)被混在一起旷痕,并且已經(jīng)很難分清了。因此顽冶,在這種情況下欺抗,我們就需要采取一些措施來(lái)協(xié)調(diào)它們對(duì)緩沖區(qū)的修改。這通常就會(huì)涉及同步强重。
概括來(lái)講绞呈,同步的用途有兩個(gè)贸人,一個(gè)是避免多個(gè)線程在同一時(shí)刻操作同一個(gè)數(shù)據(jù)塊,另一個(gè)是協(xié)調(diào)多個(gè)線程佃声,以避免它們?cè)谕粫r(shí)刻執(zhí)行同一個(gè)代碼塊艺智。

demo1

var i []int
var lock *sync.Mutex

func init() {
    lock = &sync.Mutex{}
    i = make([]int, 1)
}

func A() {
    update("A", 1)
}

func B() {
    update("B", 2)
}

func update(name string, v int) {
    //lock.Lock()
    //defer lock.Unlock()
    i[0] = v
    time.Sleep(1000)
    fmt.Printf("%s-%d\n", name, i[0])
}

func MutexTest1() {
    for i := 0; i < 10; i++ {
        go A()
    }
    for i := 0; i < 10; i++ {
        go B()
    }
}

期望輸出的結(jié)果是:
A-1
B-2
實(shí)際輸出的結(jié)果:
A-1, A-2 ,B-1, B-2 都是有可能。
這顯然與他們各自的預(yù)期結(jié)果是不符合圾亏。

臨界區(qū)(critical section)

上述例子中的‘i’就是一個(gè)共享資源十拣,一個(gè)線程在想要訪問(wèn)某一個(gè)共享資源的時(shí)候,需要先申請(qǐng)對(duì)該資源的訪問(wèn)權(quán)限志鹃,并且只有在申請(qǐng)成功之后夭问,訪問(wèn)才能真正開(kāi)始。而當(dāng)線程對(duì)共享資源的訪問(wèn)結(jié)束時(shí)曹铃,它還必須歸還對(duì)該資源的訪問(wèn)權(quán)限缰趋,若要再次訪問(wèn)仍需申請(qǐng)。你可以把這里所說(shuō)的訪問(wèn)權(quán)限想象成一塊令牌陕见,線程一旦拿到了令牌埠胖,就可以進(jìn)入指定的區(qū)域,從而訪問(wèn)到資源淳玩,而一旦線程要離開(kāi)這個(gè)區(qū)域了,就需要把令牌還回去非竿,絕不能把令牌帶走蜕着。如果針對(duì)某個(gè)共享資源的訪問(wèn)令牌只有一塊,那么在同一時(shí)刻红柱,就最多只能有一個(gè)線程進(jìn)入到那個(gè)區(qū)域承匣,并訪問(wèn)到該資源。這時(shí)锤悄,我們可以說(shuō)韧骗,多個(gè)并發(fā)運(yùn)行的線程對(duì)這個(gè)共享資源的訪問(wèn)是完全串行的。只要一個(gè)代碼片段需要實(shí)現(xiàn)對(duì)共享資源的串行化訪問(wèn)零聚,就可以被視為一個(gè)臨界區(qū)(critical section)袍暴,也就是我剛剛說(shuō)的,由于要訪問(wèn)到資源而必須進(jìn)入的那個(gè)區(qū)域隶症。如果針對(duì)同一個(gè)共享資源政模,這樣的代碼片段有多個(gè),那么它們就可以被稱為相關(guān)臨界區(qū)蚂会。

同步工具

臨界區(qū)總是需要受到保護(hù)的淋样,否則就會(huì)產(chǎn)生競(jìng)態(tài)條件。施加保護(hù)的重要手段之一胁住,就是使用實(shí)現(xiàn)了某種同步機(jī)制的工具趁猴,也稱為同步工具刊咳。在Go語(yǔ)言中,可供我們選擇的同步工具并不少儡司。其中娱挨,最重要且最常用的同步工具當(dāng)屬互斥量(mutual exclusion,簡(jiǎn)稱mutex)枫慷。sync包中的Mutex就是與其對(duì)應(yīng)的類型让蕾,該類型的值可以被稱為互斥量或者互斥鎖。

所以說(shuō)鎖其實(shí)是一種同步工具或听,能消除競(jìng)態(tài)條件探孝,保護(hù)共享數(shù)據(jù)的數(shù)據(jù)的一致性。

都有哪些鎖誉裆,怎么用顿颅?

go語(yǔ)言的sync包下實(shí)現(xiàn)了兩種鎖。sync.Mutex (互斥鎖)和 sync.RWMutex(讀寫(xiě)鎖)足丢。
sync.Cond有些地方稱為條件變量粱腻,有些稱為條件鎖。這個(gè)看你怎么理解了斩跌。

sync.Mutex (互斥鎖mutual exclusion绍些,簡(jiǎn)稱mutex)

如demo1

func update(name string, v int) {
    lock.Lock()
    defer lock.Unlock()
    i[0] = v
    time.Sleep(1000)
    fmt.Printf("%s-%d\n", name, i[0])
}

一個(gè)互斥鎖可以被用來(lái)保護(hù)一個(gè)臨界區(qū)或者一組相關(guān)臨界區(qū)。我們可以通過(guò)它來(lái)保證耀鸦,在同一時(shí)刻只有一個(gè)goroutine處于該臨界區(qū)之內(nèi)柬批。為了兌現(xiàn)這個(gè)保證,每當(dāng)有g(shù)oroutine想進(jìn)入臨界區(qū)時(shí)袖订,都需要先對(duì)它進(jìn)行鎖定氮帐,并且,每個(gè)goroutine離開(kāi)臨界區(qū)時(shí)洛姑,都要及時(shí)地對(duì)它進(jìn)行解鎖上沐。
鎖定操作可以通過(guò)調(diào)用互斥鎖的Lock方法實(shí)現(xiàn),而解鎖操作可以調(diào)用互斥鎖的Unlock方法楞艾。

使用互斥鎖的注意事項(xiàng)如下:

1.不要重復(fù)鎖定互斥鎖参咙;(避免死鎖)
2.不要忘記解鎖互斥鎖,必要時(shí)使用defer語(yǔ)句产徊;(防止忘記解鎖)
3.不要對(duì)尚未鎖定或者已解鎖的互斥鎖解鎖昂勒;(會(huì)panic)
4.不要在多個(gè)函數(shù)之間直接傳遞互斥鎖。(順序和鎖的次數(shù)有錯(cuò)亂的可能造成死鎖)

死鎖

所謂的死鎖舟铜,指的就是當(dāng)前程序中的主goroutine戈盈,以及我們啟用的那些goroutine都已經(jīng)被阻塞。這些goroutine可以被統(tǒng)稱為用戶級(jí)的goroutine。這就相當(dāng)于整個(gè)程序都已經(jīng)停滯不前了塘娶。Go語(yǔ)言運(yùn)行時(shí)系統(tǒng)是不允許這種情況出現(xiàn)的(目前還沒(méi)接觸過(guò)允許死鎖的語(yǔ)言)归斤,只要它發(fā)現(xiàn)所有的用戶級(jí)goroutine都處于等待狀態(tài),就會(huì)自行拋出一個(gè)帶有如下信息的panic:
fatal error: all goroutines are asleep - deadlock!
注意刁岸,這種由Go語(yǔ)言運(yùn)行時(shí)系統(tǒng)自行拋出的panic都屬于致命錯(cuò)誤脏里,都是無(wú)法被恢復(fù)的,調(diào)用recover函數(shù)對(duì)它們起不到任何作用虹曙。也就是說(shuō)迫横,一旦產(chǎn)生死鎖,程序必然崩潰酝碳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矾踱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疏哗,更是在濱河造成了極大的恐慌呛讲,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件返奉,死亡現(xiàn)場(chǎng)離奇詭異贝搁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芽偏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門雷逆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人污尉,你說(shuō)我怎么就攤上這事关面。” “怎么了十厢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)捂齐。 經(jīng)常有香客問(wèn)我蛮放,道長(zhǎng),這世上最難降的妖魔是什么奠宜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任包颁,我火速辦了婚禮,結(jié)果婚禮上压真,老公的妹妹穿的比我還像新娘娩嚼。我一直安慰自己,他們只是感情好滴肿,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布岳悟。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贵少。 梳的紋絲不亂的頭發(fā)上呵俏,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音滔灶,去河邊找鬼普碎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛录平,可吹牛的內(nèi)容都是我干的麻车。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼斗这,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼动猬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起涝影,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤枣察,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后燃逻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體序目,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年伯襟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猿涨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姆怪,死狀恐怖叛赚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稽揭,我是刑警寧澤俺附,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站溪掀,受9級(jí)特大地震影響事镣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揪胃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一璃哟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喊递,春花似錦随闪、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春盛杰,著一層夾襖步出監(jiān)牢的瞬間挽荡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工即供, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留定拟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓逗嫡,卻偏偏與公主長(zhǎng)得像青自,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驱证,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350