Go并发编程中锁机制的常见错误:为什么1000个协程累加结果并非1000?

go并发编程中锁机制的常见错误:为什么1000个协程累加结果并非1000?

Go并发编程中的sync.Mutex锁及常见错误分析

本文剖析一段使用sync.Mutex锁和sync.WaitGroup进行并发编程的Go代码,这段代码试图通过1000个协程累加一个变量,但最终结果与预期(1000)不一致。让我们来分析代码并找出问题所在。

示例代码:

package mainimport (    "fmt"    "sync"    "time")func main() {    haslockandwait()}func haslockandwait() {    var a = 0    var wg sync.WaitGroup    for i := 0; i < 1000; i++ {        wg.Add(1)        go func(i int) {            defer wg.Done()            var locker sync.Mutex // 错误:锁声明在此处            locker.Lock()            a++            locker.Unlock()        }(i)    }    wg.Wait()    fmt.Println("最终结果:", a)}

代码预期结果是a最终值为1000,但实际运行结果往往小于1000。这是因为sync.Mutex的声明位置错误。

问题根源:var locker sync.Mutex这行代码在每个goroutine内部声明,这意味着每个goroutine都创建了一个独立的sync.Mutex实例。这些锁互不干扰,多个goroutine可以同时修改a,导致结果不准确。

解决方案:将sync.Mutex的声明移到for循环之外,使其成为全局锁,确保所有goroutine使用同一个锁来保护a变量。修改后的代码如下:

func hasLockAndWait() {    var a = 0    var wg sync.WaitGroup    var locker sync.Mutex // 正确:锁声明在此处    for i := 0; i < 1000; i++ {        wg.Add(1)        go func(i int) {            defer wg.Done()            locker.Lock()            a++            locker.Unlock()        }(i)    }    wg.Wait()    fmt.Println("最终结果:", a)}

另一种更简洁高效的解决方案是使用atomic.AddInt64函数,它提供原子操作,无需锁即可保证线程安全:

import "sync/atomic"func atomicAdd() {    var a int64 = 0    var wg sync.WaitGroup    for i := 0; i < 1000; i++ {        wg.Add(1)        go func() {            defer wg.Done()            atomic.AddInt64(&a, 1)        }()    }    wg.Wait()    fmt.Println("最终结果:", a)}

通过以上修改,可以确保并发累加操作的正确性,最终结果将为1000。 这强调了在Go并发编程中正确使用锁机制的重要性,错误的锁使用会导致数据竞争和不正确的程序行为。

以上就是Go并发编程中锁机制的常见错误:为什么1000个协程累加结果并非1000?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1386196.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月15日 06:05:44
下一篇 2025年12月15日 06:05:56

相关推荐

发表回复

登录后才能评论
关注微信