Golang Go语言中有一段代码报了 race,但不知道会有什么潜在问题,各位大佬帮忙指点一下

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

Golang Go语言中有一段代码报了 race,但不知道会有什么潜在问题,各位大佬帮忙指点一下

代码如下:

package main

import (
	"sync"
	"sync/atomic"
)

func main() {
	var n int32
	var m sync.RWMutex
	go func() {
		for {
			atomic.LoadInt32(&n)
		}
	}()
	go func() {
		for {
			m.RLock()
			atomic.AddInt32(&n, 1)
			m.RUnlock()
		}
	}()
	go func() {
		for {
			m.Lock()
			n = 0
			m.Unlock()
		}
	}()
	go func() {
		for {
			m.Lock()
			n -= 1
			m.Unlock()
		}
	}()
    // do something to keep goroutines running here
	......
}

playground link: https://play.golang.org/p/Mrdetw46mXR

race 内容:

$ go run -race main.go
==================
WARNING: DATA RACE
Write at 0x00c000096000 by goroutine 7:
  main.main.func3()
      /Users/purewhite/go/src/xxx/main.go:26 +0x46

Previous read at 0x00c000096000 by goroutine 5: sync/atomic.LoadInt32() /usr/local/Cellar/go/1.12.6/libexec/src/runtime/race_amd64.s:206 +0xb main.main.func1() /Users/purewhite/go/src/xxx/main.go:13 +0x38

Goroutine 7 (running) created at: main.main() /Users/purewhite/go/src/xxx/main.go:23 +0x115

Goroutine 5 (running) created at: main.main() /Users/purewhite/go/src/xxx/main.go:11 +0xbd

Found 1 data race(s) exit status 66


更多关于Golang Go语言中有一段代码报了 race,但不知道会有什么潜在问题,各位大佬帮忙指点一下的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

把 mutex 去了,
用 atomic.StoreInt32(&n, 0) 代替 n = 0
用 atomic.AddInt32(&n, -1) 代替 n -= 1

更多关于Golang Go语言中有一段代码报了 race,但不知道会有什么潜在问题,各位大佬帮忙指点一下的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


为啥你修改要用读锁?

这写法看着真别扭。很明显第一个协程和第三第四个有竞争。
按照你这种写法,你可以把第一个和第二个一样加个读锁。

为什么原子操作还加锁

要么全部用锁,要么全部用原子操作,混用就是 race 啊

在Go语言中,遇到race(数据竞争)问题通常意味着你的程序在并发环境下存在多个goroutine同时访问(读或写)同一个变量,且至少有一个访问是写操作,但这些访问没有被正确地同步。数据竞争会导致未定义行为,包括但不限于:

  1. 数据不一致:多个goroutine可能看到同一个变量的不同值,导致程序逻辑错误。
  2. 程序崩溃:由于并发访问导致的内存访问冲突,程序可能会崩溃。
  3. 死锁:如果使用了不当的锁机制尝试解决数据竞争,可能会导致死锁,使得程序无法继续执行。

解决数据竞争的关键在于确保所有对共享变量的访问都是安全的。这通常通过以下几种方式实现:

  • 使用互斥锁(sync.Mutex):保护对共享变量的访问,确保同一时间只有一个goroutine可以访问。
  • 使用通道(channel):通过通道在goroutine之间传递数据,避免直接共享变量。
  • 使用原子操作(sync/atomic包):对于简单的计数器等场景,可以使用原子操作来确保并发安全。

建议使用Go的race detector工具来定位具体的数据竞争位置。在运行程序时添加-race标志,如go run -race your_program.go,它会帮助你找到并修复代码中的竞争条件。

总之,解决数据竞争是确保Go程序并发安全的关键,务必认真对待并彻底修复。

回到顶部