登录
首页 >  Golang >  Go教程

Go 中 sync.Mutex 锁失效之谜:为什么在并发访问共享变量时,使用 sync.Mutex 并不能保证结果正确?

时间:2024-11-19 16:55:16 302浏览 收藏

在Golang实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《Go 中 sync.Mutex 锁失效之谜:为什么在并发访问共享变量时,使用 sync.Mutex 并不能保证结果正确?》,聊聊,希望可以帮助到正在努力赚钱的你。

Go 中 sync.Mutex 锁失效之谜:为什么在并发访问共享变量时,使用 sync.Mutex 并不能保证结果正确?

sync.mutex 锁失效之谜

在探索 go 中并发的 sync.mutex 时,一位新手遇到了令人困惑的问题。他们编写了一个程序,目标是使用 1000 个协程对一个变量加 1000,每个协程 +1,并期待最终结果为 1000。

然而,代码执行后,却得到了随机的结果,让新手心灰意冷。问题出在哪里?

问题代码分析

var a = 0
var wg sync.waitgroup

for i := 0; i < 1000; i++ {
    wg.add(1)

    go func() {
        defer wg.done()
        var locker sync.mutex
        locker.lock()
        defer locker.unlock()
        a++
        fmt.println("a 的值为:", a)
    }()
}

新手使用的 sync.mutex 旨在控制对共享变量 a 的访问,确保同一时刻只有一个协程操作它。但是,问题在于 locker.lock() 和 locker.unlock() 被放置在匿名函数内部,而不是for循环中。

解决方案

为了解决这个问题,只需将 locker.lock() 和 locker.unlock() 移动到 for 循环中。这样,每个协程都会使用自己的 locker 对象,从而实现正确的锁定机制。

var locker sync.mutex

for i := 0; i < 1000; i++ {
    wg.add(1)

    go func() {
        defer wg.done()
        locker.lock()
        defer locker.unlock()
        a++
        fmt.println("a 的值为:", a)
    }()
}

另一种选择是使用 atomic.addint64() 函数,它提供了一种线程安全的原子操作,可以直接对变量进行加减。

func hasLockAndWait() {
    var a int64 // 使用 int64 以匹配 atomic.AddInt64()

    for i := 0; i < 1000; i++ {
        wg.Add(1)

        go func() {
            defer wg.Done()
            atomic.AddInt64(&a, 1)
            fmt.Println("a 的值为:", a)
        }()
    }

    wg.Wait()
    fmt.Println("a 的最终值为:", a)
}

通过采用这些解决方案,新手应该能够获得预期的结果:变量 a 的最终值为 1000。

到这里,我们也就讲完了《Go 中 sync.Mutex 锁失效之谜:为什么在并发访问共享变量时,使用 sync.Mutex 并不能保证结果正确?》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>