golang中的互斥锁
簡介
每個資源都對應一個可稱為"互斥鎖"的標記,這個標記用來保證在任意時刻,只有一個協程(線程)訪問該資源.其他的協程只能等待
由標準庫sync中的Mutex結構體類型表示.
sync.Mutex類型只有兩個公開的指針方法,Lock和Unlock.
Lock鎖定當前的共享資源,Unlock進行解鎖
使用互斥鎖時,一定要注意:對資源操作完成后,一定要解鎖,否則出現流程執行異常,死鎖問題.通常借助defer.鎖定后,立即使用defer語句保證互斥鎖及時解鎖
var mutex sync.Mutex //定義互斥鎖變量func write() {muter.Lock()defer muter.Unlock() }使用
//新創建為0.表示沒有加鎖,鎖只有1把 var mutex sync.Mutexfunc printer(str string) {mutex.Lock()for _, ch := range str {fmt.Println(string(ch))time.Sleep(300 * time.Millisecond)}//共享數據訪問結束mutex.Unlock() }func person1() {printer("11") }func person2() {printer("222") }func main() {//先,因為他先獲得鎖go person1()//后go person2()for {;} }不是強制性的
互斥鎖的使用是主動控制互斥鎖,即一個愿打一個愿挨。比如即使一個routine里用了Lock(),但在另一個routine可以不理會這個鎖就能訪問這個struct,只需要不調用Lock()就行。例子如下
package mainimport ("fmt""sync""time" )type SafeCounter struct {v map[string]intmux sync.Mutex }func (c *SafeCounter) Inc(key string) {c.mux.Lock()time.Sleep(3 * time.Second)c.v[key]++c.mux.Unlock() }func main() {c := SafeCounter{v: make(map[string]int)}go c.Inc("somekey")time.Sleep(1 * time.Second)c.v["somekey"]++fmt.Println(c.v["somekey"])time.Sleep(3 * time.Second)fmt.Println(c.v["somekey"]) }輸出
1 2c.v["somekey"]++之前,是已經鎖了,本應該等2-3秒,才能輸出,但是從程序開始運行,只過了1秒就輸出了,說明Lock只是一種人為的互斥,是一種協議,并不是強制。
已經鎖定的Mutex與特定的goroutine無關聯
已經鎖定的Mutex并不與特定的goroutine相關聯,這樣可以利用一個goroutine對其加鎖,再利用其他goroutine對其解鎖,例子如下
package mainimport ("fmt""sync""time" )type MyStruct struct {v intmux sync.Mutex }func (s *MyStruct) Lock() {s.mux.Lock() }func (s *MyStruct) Unlock() {s.mux.Unlock() }func main() {s := MyStruct{v: 0}s.v = 1fmt.Printf("%+v\n", s)go s.Lock()time.Sleep(1 * time.Second)fmt.Printf("%+v\n", s)go s.Unlock()time.Sleep(1 * time.Second)fmt.Printf("%+v\n", s) }輸出
{v:1 mux:{state:0 sema:0}} {v:1 mux:{state:1 sema:0}} {v:1 mux:{state:0 sema:0}}可以看出,可以一個routine里鎖定,另一個routine里解鎖。因為鎖只和具體變量關聯,和routine無關,只要這個變量是共享的,比如通過指針傳遞,或者全局變量都可以。
雖然互斥鎖可以被直接的在多個Goroutine之間共享,但是我們還是強烈建議把對同一個互斥鎖的成對的鎖定和解鎖操作放在同一個層次的代碼塊中。例如,在同一個函數或方法中對某個互斥鎖的進行鎖定和解鎖。
總結
以上是生活随笔為你收集整理的golang中的互斥锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang中的死锁
- 下一篇: golang中的读写锁