Golang Go语言中关于互斥锁的一个疑问

发布于 1周前 作者 vueper 来自 Go语言

Golang Go语言中关于互斥锁的一个疑问

代码见 https://github.com/GramYang/GoTest/blob/master/sync/mutex1.go

第一个 test 输出的是小于 1000 的随机值。 第二个 test 稳定输出 1000,但是限制了原生线程的数量,这在工作环境中显然是不可能的。 第三个 test 稳定输出 1000,方法和我之前用过的 currenthashmap 的用法一样。这里已经去掉了互斥锁。

那么问题来了:既然互斥锁锁的只是 goroutine,而多个原生线程并发仍然会产生并发错误,那么到底该怎么正确使用互斥锁呢?


更多关于Golang Go语言中关于互斥锁的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

下面是 go playground 的输出。
func passes lock by value: sync.Mutex
这一句, 锁不能用值传递, 改成全局变量或者放在结构体里面再试。


./prog.go:38:8: call of func(i int, m sync.Mutex) {
fmt.Println("Not lock: ", i)
mutex.Lock()
fmt.Println("Lock: ", i)
time.Sleep(time.Second)
fmt.Println("Unlock: ", i)
mutex.Unlock()
defer wait.Done()
} copies lock value: sync.Mutex
./prog.go:30:20: func passes lock by value: sync.Mutex
./prog.go:58:8: call of func(c *counter, m sync.Mutex) {
m.Lock()
defer m.Unlock()
c.value++
wg.Done()
} copies lock value: sync.Mutex
./prog.go:53:25: func passes lock by value: sync.Mutex
Go vet exited.

数数:1000

play.go

更多关于Golang Go语言中关于互斥锁的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


把锁换成指针传递后可以了。。。。。

#2

type counter struct {
sync.Mutex
value int
}

func test2() {
runtime.GOMAXPROCS(1)
var wg sync.WaitGroup
wg.Add(1000)
c := new(counter)
c.value=0
for i := 0; i < 1000; i++ {
go func(c *counter) {
c.Lock()
defer c.Unlock()
c.value++
wg.Done()

}
wg.Wait()
fmt.Println(“数数:”, c.value)
}

func main() {
test2()
}

[官方文档]( https://godoc.org/sync) 第一段话说了:

> Values containing the types defined in this package should not be copied.

想起了以前偷懒这样写

client := &http.Client{}
t := *( http.DefaultTransport.(*http.Transport))
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client.Transport = http.RoundTripper(&t)

结果高并发时 http 内部锁随机炸

关于您在Golang(Go语言)中提到的互斥锁疑问,我很乐意为您提供一些专业的解答。

在Go语言中,互斥锁(Mutex)是一种常用的同步机制,用于保护共享资源,防止多个goroutine同时访问导致的数据竞争和不一致性问题。使用互斥锁时,需要注意以下几点:

  1. 加锁与解锁:在访问共享资源前,应使用mutex.Lock()方法加锁,确保当前goroutine独占该资源。访问完毕后,应使用mutex.Unlock()方法解锁,以便其他goroutine可以访问。

  2. 避免死锁:加锁后,务必确保在适当的时机解锁。如果加锁后发生异常或goroutine被阻塞,可能导致死锁。因此,通常建议使用defer mutex.Unlock()来确保在函数返回前解锁。

  3. 锁的重入性:Go的互斥锁不是可重入的。如果一个goroutine已经持有一个互斥锁,再次尝试加锁会导致该goroutine永久阻塞。

  4. 性能考虑:虽然互斥锁能有效防止数据竞争,但也会引入额外的开销。因此,在性能敏感的场景下,应谨慎使用,并考虑其他并发控制手段,如channel、select等。

希望以上解答能帮您解决关于Go语言中互斥锁的疑问。如有其他问题或需要更详细的解释,请随时提问。

回到顶部