Go语言中的潜在竞态条件

huangapple go评论92阅读模式
英文:

potential race condition in go language

问题

我不确定为什么以下代码存在竞态条件,有人可以给我一个提示吗?我认为没有潜在的竞态条件。提前谢谢。

type PossiblySafeCounter struct {
    mu sync.Mutex
    sum int
}

func (c *PossiblySafeCounter) inc() {
   c.mu.Lock();
   defer c.mu.Unlock();
   go func() {
       c.sum++
   }() 
}
func (c *PossiblySafeCounter) read() int {
    c.mu.Lock();
    defer c.mu.Unlock();
    return c.sum
}

以下是翻译好的部分。

英文:

I am not sure why the following code has the race condition, can someone give me a hint? I think there is no potential race condition. Thank you in advance.

type PossiblySafeCounter struct {
    mu sync.Mutex
    sum int
}

func (c *PossiblySafeCounter) inc() {
   c.mu.Lock();
   defer c.mu.Unlock();
   go func() {
       c.sum++
   }() 
}
func (c *PossiblySafeCounter) read() int {
    c.mu.Lock();
    defer c.mu.Unlock();
    return c.sum
 }

答案1

得分: 6

c.sum++ 在一个独立于 inc() 方法执行的 goroutine 中调度。当 inc() 方法退出时,延迟的互斥锁解锁很可能会在错误的时间发生,导致竞态条件。

如 @Flimzy 建议,使用 atomic.AddInt32 可以完全避免使用互斥锁。

基于互斥锁的两种解决方案要么不在 goroutine 中进行递增操作:

func (c *PossiblySafeCounter) inc() {
   c.mu.Lock()
   defer c.mu.Unlock()
   c.sum++
}

要么在 goroutine 中进行锁定和解锁操作:

func (c *PossiblySafeCounter) inc() {
   go func() {
       c.mu.Lock()
       defer c.mu.Unlock()
       c.sum++
   }()
}

但是,老实说,在这个例子中使用任何类型的 goroutine 都没有意义。为什么需要在 goroutine 中进行递增操作呢?

英文:

The c.sum++ is in a goroutine that is scheduled independently of the execution of the inc() method. When the inc() method exits the defered unlock of the mutex will happen and will very likely happen at the wrong time, leading to a race condition.

As @Flimzy suggests using atomic.AddInt32 would remove the need for a mutex at all.

two mutex based solutions are either to not increment in a goroutine:

func (c *PossiblySafeCounter) inc() {
   c.mu.Lock();
   defer c.mu.Unlock();
   c.sum++
}

or do the locking and unlocking in the goroutine:

func (c *PossiblySafeCounter) inc() {
   go func() {
       c.mu.Lock();
       defer c.mu.Unlock();
       c.sum++
   }() 
}

but honestly, doing any kind of goroutine doesn't make sense in this example. Why do you need the increment to be in a goroutine?

huangapple
  • 本文由 发表于 2017年4月15日 08:38:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/43420958.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定