In much of the programming universe, the preferred method of synchronization between two or more concurrent processes is the mutex. And for good reason: mutexes (mutices?) provide a very simple tool that is easy to understand, and once you acquire that understanding you can use it to build arbitrarily complex concurrent systems.
The problem is that what you want as the programmer is rarely limited to exactly what a mutex gives you. Most of the time you need something a bit more complex, and although the more complex operation can be built out of mutexes, small errors become huge bugs which can be difficult to fix or even just observe (heisenbugs).
In this post I will demonstrate how to build a useful real-world concurrent system, first using mutexes and then using the more advanced tools that go offers.
The system in question is a notification multiplexor. One process, which I’ll call the Listener, will receive notifications from an outside source. Some number of other processes, which I will call the Subscribers, need to collect these notifications.