package main
import (
"sync"
"strconv"
"fmt"
)type node struct
var cache node;
func main()
cache[1] = node
wg := sync.waitgroup{}
for i := 0; i < 10000; i++ (i)
} wg.wait();
fmt.println(cache[0])
}
看上面這塊**邏輯很簡單,併發10000個協程對cache中的data進行賦值,偶數index
就賦值到第0
個map,奇數就賦值第1
個map,並且map賦值的時候都加了鎖,但是在golang 1.8 執行的時候會爆出如下錯誤
fatal error: concurrent map writes
fatal error: concurrent map writes
goroutine 26 [running]:
runtime.throw(0x10b4392, 0x15)
......
為什麼加鎖了仍然會報cuncurrent map wirtes,這一定是golang 1.8 的bug(開玩笑的……)!
主要原因是golang的struct 在賦值的時候是進行淺拷貝,把結構體的成員進行了copy,node 結構體有兩個成員
type node struct
我們從slice中把node拿出來的時候,其實是copy了乙份node,map是指標型別的,所以多份copy其實是操作乙份map,但是sync.mutex型別是struct,他進行了一次copy
所以在每個協程中取出來的時候,mutex都進行了一次copy,lock的時候不是同乙份鎖,所以會出現併發map寫入。
把node的成員mutex 改成指標型別,那麼在copy的時候,mutex 能保持對同乙份進行lock,**如下
package main
import (
"fmt"
"strconv"
"sync"
)type node struct
var cache node
func main() }
cache[1] = node}
wg := sync.waitgroup{}
for i := 0; i < 10000; i++ (i)
} wg.wait()
fmt.println(cache[0])
}
mutex 改成指標型別即可保證同乙份鎖。
cache中如果是node指標型別,那麼index訪問的時候,拿出來是指標的副本,指向的仍然是同乙份位址,加鎖的時候仍然訪問的是同乙份資源
**如下
package main
import (
"fmt"
"strconv"
"sync"
)type node struct
var cache *node
func main()
cache[1] = &node
wg := sync.waitgroup{}
for i := 0; i < 10000; i++ (i)
} wg.wait()
fmt.println(cache[0])
}
golang 類似於c++,系統提供的賦值都是淺拷貝,如果確認需要對同乙份內容進行訪問的時候,需要在特定的地方用上指標 golang 併發鎖在struct裡的陷阱
type test struct func main buf 1 test var wg sync.waitgroup for i 0 i 100 i i wg.wait 結果是報cuncurrent map wirtes 原因 從slice中把拿出來其實是拷貝的,而struct 在賦值的時候是進行...
Golang 併發之互斥鎖
當多個goroutine同時訪問乙個資源的時候需要加上互斥鎖防止出錯。互斥鎖能保證同時只有乙個goroutine訪問共享資源。go語言中使用sync包的mutex型別詩選互斥鎖。go語言中對 mutex 的定義 a mutex is a mutual exclusion lock.the zero ...
golang 之sync 併發安全鎖
讓乙個程式併發安全並不需要其中的每乙個具體型別都是併發安全的。實際上併發安全的型別其實是特例而不是普遍存在的,所以僅在文件指出型別是安全的情況下,才可以併發的訪問乙個變數。與之對應的是,匯出的包級別函式通常可以認為是併發安全的。因為包級別的變數無法限制在乙個goroutine內。所以那些修改這些變數...