On Sat, Apr 14, 2018 at 10:02 AM, Penguin Enormous <kimkhanh...@gmail.com> wrote: > > Could it be this: > > Initially wait == notify == 0 > > Waiter Signaler > > 479 atomic.Xadd(&l.wait, 1) = 1 > > 522 atomic.Load(&l.wait) = 0 > atomic.Load(&l.notify) = 0 > > 523 return (because those above are equal) > > 485 notifyListWait(l, t) (blocked forever) > > But looking at your answer, I see that you may imply certain race conditions > are allowed. Could you explain a bit more on that? Aren't race conditions > supposedly bad? > > If atomic load should always returns the last atomic write to a memory > location and if I make absolutely sure that the last atomic write finish at > a specific time instant earlier than the atomic load, I can never get data > written before that last atomic write, is that what you meant?
I didn't mean to imply that data races are OK. I meant that when using condition variables, you have to be aware of the race conditions between Wait and Signal/Broadcast, and you have to mitigate those race conditions through correct use of the Locker associated with the condition variable. These race conditions are not data race conditions, they are rather logical race conditions, in the sense that if you do not correctly use the Locker then your goroutines can indeed block forever in Wait. You are describing the possible race in terms of the runtime code, which is the wrong level. You need to try to describe it in terms of the sync.Cond methods. If you do that you see that the atomic increment of l.wait is done with Locker locked. Then the Locker is unlocked, and the code calls notifyListWait. The loads of l.wait and l.notify are done by the Signal and Broadcast methods. While the Signal and Broadcast methods do not require the Locker to be locked, if you want to ensure that they wake up all waiting goroutines there must be some sort of happens-before relationship between the waiting goroutine and the signaling goroutine. If there is no happens-before relationship, then in theory the signal could happen before the wait, in which case obviously the wait won't see the signal; that's just how condition variables work. For your program to work as expected, it must be the case that the wait happens-before the signal. And the obvious way to do that is to acquire the lock before signaling. Acquire the lock, verify that there is something to signal, and then signal (releasing the lock before signaling is optional). This is how condition variables work in any language, it's not specific to Go. And this is the reason why condition variables are very rarely used in Go. It is much easier to reason correctly about channels and mutexes than it is to reason about condition variables. Therefore, Go programs prefer channels and mutexes when at all possible. Ian -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.