Cond

Cond implements a condition variable, a rendezvous point for goroutines waiting for or announcing the occurrence of an event.

Broadcast

A typical use case for Broacast is when multiple goroutines are waiting for something to happen. In order to let all of them that a certain event happened using channels, then we would need to have one channel for each of them. And then send each of them a message. This is what Broadcast is about. Broadcast wakes all goroutines waiting on that Condso that they can continue working.

Inside a Cond type, there is an attribute called notify of type notifyList. notify is used by a function called runtime_notifyListNotifyAll in order to wake up all goroutines.

func (c *Cond) Broadcast() { c.checker.check() runtime_notifyListNotifyAll(&c.notify) }

And even when it's not necessary to understand how Broadcastworks, if we peek at runtime_notifyListNotifyAll implementation, we can actually verify that it readies all the outstanding goroutines by calling goready.


// notifyListNotifyAll notifies all entries in the list.

//go:linkname notifyListNotifyAll sync.runtime_notifyListNotifyAll

func notifyListNotifyAll(l *notifyList) {
	// Fast-path: if there are no new waiters since the last notification
	// we don't need to acquire the lock.
	if atomic.Load(&l.wait) == atomic.Load(&l.notify) {
		return
	}
    /* 
    ommited code
    */
    s := l.head
    /* 
    ommited code
    */
	for s != nil {
		next := s.next
		s.next = nil
		readyWithTime(s, 4) // this function calls goready
		s = next
	}
}

Signal

Signal will only wake one goroutine, if there was at least one waiting.

The implementation is similar to the one for Broadcast. This time, it relies on a helper function called notifyListNotifyOne.

Wait

Cond has an associated Locker (which normally is a *Mutex or *RWMutex). This Locker must be held when calling the Wait method.

If there's a goroutine that needs to be awaken to do some work, it can be modelled as follow:

go func(c *sync.Cond) {
    // hold the Locker when calling the wait method
    c.L.Lock()
    for !condition() {
        c.Wait()
    }
    // ... make use of condition ...
    c.L.Unlock()
    // Unlock the Locker when its done
}

For completeness, a Locker is just an interface that defines two methods: Lock and Unlock.