golang之讀寫鎖,互斥鎖的理解

2021-10-05 23:10:37 字數 3689 閱讀 6536

golang sync包裡提供了 locker介面、互斥鎖 mutex、讀寫鎖 rwmutex用於處理併發過程中可能出現同時兩個或多個協程(或執行緒)讀或寫同乙個變數的情況。

在併發的情況下,多個執行緒或協程同時去修改乙個變數。使用鎖能保證在某一時間點內,只有乙個協程或執行緒修改這一變數,具體我們可以看示例。先看不加鎖的程式(會出現多個程式同時讀該變數):

package main

import (

"fmt"

"time"

)func main() (i)

}time.sleep(time.second)

}

從理論上來說,上面的函式是每次遞增a的值的,所以理論上應該會有1000個不同的值輸出,實際結果呢?

[root@361way test]# go run l1.go |sort|uniq |wc -l

998[root@361way test]# go run l1.go |sort|uniq |wc -l

1000

[root@361way test]# go run l1.go |sort|uniq |wc -l

998[root@361way test]# go run l1.go |sort|uniq |wc -l

999

協程依次執行:從暫存器讀取 a 的值 -> 然後做加法運算 -> 最後寫到暫存器。試想,此時乙個協程取出 a 的值 3,正在做加法運算(還未寫回暫存器)。同時另乙個協程此時去取,取出了同樣的 a 的值 3。最終導致的結果是,兩個協程產出的結果相同,a 相當於只增加了 1。

所以,鎖的概念就是,我正在處理 a(鎖定),你們誰都別和我搶,等我處理完了(解鎖),你們再處理。這樣就實現了,同時處理 a 的協程只有乙個,就實現了同步。

上面的示例**現的問題怎麼解決?加乙個互斥鎖 mutex就ok了。哪什麼是互斥鎖 ?其有兩個方法可以呼叫,如下:

func (m *mutex) lock()

func (m *mutex) unlock()

我們改下迴圈遞增示例中的**,如下:

package main

import (

"fmt"

"time"

)func main() (i)

}// 等待 1s 結束主程式

// 確保所有協程執行完

time.sleep(time.second)

}

修改後執行的結果總是1000個不重服的值。而且使用go語言的lock鎖一般不會出現忘了解鎖的情況,因類其緊跟鎖定的就是defer unlock 。

需要注意的是乙個互斥鎖只能同時被乙個 goroutine 鎖定,其它 goroutine 將阻塞直到互斥鎖被解鎖(重新爭搶對互斥鎖的鎖定)。看如下**:

package main

import (

"fmt"

"sync"

"time"

)func main() , 2)

var l sync.mutex

go func() {}

}()go func() {}

}()// 等待 goroutine 執行結束

for i := 0; i < 2; i++

}

上面的**執行結果如下:

groutine2: 等待解鎖

goroutine1: 我會鎖定大概 2s

goroutine1: 我解鎖了,你們去搶吧

groutine2: 我已經搶到鎖了

goroutine2: 歐耶,我也解鎖了

讀寫鎖有如下四個方法:

寫操作的鎖定和解鎖

* func (*rwmutex) lock

* func (*rwmutex) unlock

讀操作的鎖定和解鎖

* func (*rwmutex) rlock

* func (*rwmutex) runlock

我們怎麼理解讀寫鎖呢?當有乙個 goroutine 獲得寫鎖定,其它無論是讀鎖定還是寫鎖定都將阻塞直到寫解鎖;當有乙個 goroutine 獲得讀鎖定,其它讀鎖定仍然可以繼續;當有乙個或任意多個讀鎖定,寫鎖定將等待所有讀鎖定解鎖之後才能夠進行寫鎖定。所以說這裡的讀鎖定(rlock)目的其實是告訴寫鎖定:有很多人正在讀取資料,你給我站一邊去,等它們讀(讀解鎖)完你再來寫(寫鎖定)。

package main

import (

"fmt"

"math/rand"

"sync"

)var count int

var rw sync.rwmutex

func main() , 10)

for i := 0; i < 5; i++

for i := 0; i < 5; i++

for i := 0; i < 10; i++

}func read(n int, ch chan struct{}) {}

}func write(n int, ch chan struct{}) {}

}

其執行結果如下:

goroutine 4 進入寫操作...

goroutine 4 寫入結束,新值為:81

goroutine 2 進入讀操作...

goroutine 2 讀取結束,值為:81

goroutine 3 進入讀操作...

goroutine 3 讀取結束,值為:81

goroutine 0 進入讀操作...

goroutine 0 讀取結束,值為:81

goroutine 1 進入讀操作...

goroutine 4 進入讀操作...

goroutine 4 讀取結束,值為:81

goroutine 1 讀取結束,值為:81

goroutine 0 進入寫操作...

goroutine 0 寫入結束,新值為:887

goroutine 1 進入寫操作...

goroutine 1 寫入結束,新值為:847

goroutine 3 進入寫操作...

goroutine 3 寫入結束,新值為:59

goroutine 2 進入寫操作...

goroutine 2 寫入結束,新值為:81

package main

import (

"sync"

"time"

)var m *sync.rwmutex

func main()

func read(i int)

這裡例子中,多個讀操作同時讀乙個操作。雖然加了鎖,但都是讀是不受影響的。

package main

import (

"sync"

"time"

)var m *sync.rwmutex

func main()

func read(i int)

func write(i int)

由於讀寫互斥,上面這個示例中,寫開始的時候,讀必須要等寫進行完才能繼續。不然他只能繼續等待,這就像只有乙個茅坑,別我蹲著,你著急也不能去搶(為什麼?有門關著呢!)。

golang互斥鎖跟讀寫鎖

golang中sync包實現了兩種鎖mutex 互斥鎖 和rwmutex 讀寫鎖 其中rwmutex是基於mutex實現的,唯讀鎖的實現使用類似引用計數器的功能 1 互斥鎖 其中mutex為互斥鎖,lock 加鎖,unlock 解鎖,使用lock 加鎖後,便不能再次對其進行加鎖,直到利用unlock...

Golang 併發之互斥鎖

當多個goroutine同時訪問乙個資源的時候需要加上互斥鎖防止出錯。互斥鎖能保證同時只有乙個goroutine訪問共享資源。go語言中使用sync包的mutex型別詩選互斥鎖。go語言中對 mutex 的定義 a mutex is a mutual exclusion lock.the zero ...

互斥鎖和讀寫鎖

互斥鎖的型別 對資源的訪問是互斥的,即執行緒a對資源加鎖後,在a解鎖前,其他執行緒不能訪問這個加鎖的資源。互斥鎖的特點 多個執行緒訪問資源的時候是序列的 互斥鎖的使用步驟 建立乙個互斥鎖 pthread mutex t mutex 初始化這把鎖 pthread mutex init mutex,nu...