调用`sync.Cond`的`Wait()`方法并发地进行,是安全的吗?

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

Is Calling the `Wait()` method of `sync.Cond` Concurrently, Safe?

问题

根据文档,调用sync.CondWait()方法时会先执行Unlock(),那么这样做是安全的吗?

假设我们正在检查是否满足某个条件:

func sample() {
    cond = &sync.Cond{L: &sync.Mutex{}} // 可以被程序的其他部分访问

    go func() {
        cond.L.Lock()
        for !condition() {
            cond.Wait()
        }
        // 做一些操作...
        cond.L.Unlock()
    }()

    go func() {
        cond.L.Lock()
        mutation()
        cond.L.Unlock()

        cond.Signal()
    }()
}

以及:

func condition() bool {
    // 假设someSharedState是一个比bool更复杂的状态
    return someSharedState
}

func mutation() {
    // 假设someSharedState是一个比bool更复杂的状态
    // (A) 对someSharedState进行状态变更
}

由于Wait()方法执行了Unlock(),那么(A)是否需要自己进行加锁?还是说它是原子操作的?

英文:

Is calling the Wait() method of sync.Cond safe when according to the documentation, it performs an Unlock() first?

Assume we are checking for a condition to be met:

func sample() {
	cond = &sync.Cond{L: &sync.Mutex{}} // accessible by other parts of program

	go func() {
		cond.L.Lock()
		for !condition() {
			cond.Wait()
		}
		// do stuff ...
		cond.L.Unlock()
	}()

	go func() {
		cond.L.Lock()
		mutation()
		cond.L.Unlock()

		cond.Signal()
	}()
}

And:

func condition() bool {
	// assuming someSharedState is a more complex state than just a bool
	return someSharedState
}

func mutation() {
	// assuming someSharedState is a more complex state than just a bool
	// (A) state mutation on someSharedState
}

Since Wait() performs an Unlock, should (A) has a locking of it's own? Or being atomic?

答案1

得分: 2

是的,即使在调用Wait时首先调用了L.Unlock(),也是安全的,但在调用Wait和检查条件之前,必须先获取锁,因为在这种情况下,两者都不是线程安全的。

Wait会原子性地解锁c.L暂停调用的goroutine的执行。在稍后恢复执行之前,Wait会重新锁定c.L然后返回。

  1. 调用Wait的goroutine获取了锁,检查条件发现不满足。
  2. 现在它等待,但为了允许条件的更改,它需要释放锁。Wait会自动为您完成这个步骤,然后暂停goroutine的执行。
  3. 现在条件可以发生变化,最终goroutine会被BroadcastSignal唤醒。然后它会重新获取锁来再次检查条件(这必须逐个进行,以便每个等待的goroutine都能进行检查,否则将无法知道有多少个goroutine现在自由运行)。
英文:

Yes it is safe to call Wait even when it calls L.Unlock() first but it is essential that you acquired the lock before calling Wait and before checking your condition since, in this situation, both are not thread safe.

> Wait atomically unlocks c.L and suspends execution of the calling goroutine. After later resuming execution, Wait locks c.L before returning.

  1. The goroutine that calls Wait acquired the lock, checked the condition and found it to be unsatisfactory.
  2. Now it waits but in order to allow for changes of the condition it needs to give the lock back. Wait does that automatically for you and then suspends the goroutine.
  3. Now changes of the condition can happen and eventually the goroutine is awoken by Broadcast or Signal. It then acquires the lock to check the condition once again (This must happen one-by-one for each waiting goroutine or else there would be no way telling how many goroutines are running around freely now).

huangapple
  • 本文由 发表于 2015年11月27日 17:57:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/33954763.html
匿名

发表评论

匿名网友

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

确定