Let's follow on from the final example from the last section—the locking decorator. It calls any function under a lock, so no other function protected by the same mutex can be called on any other thread at the same time. In some cases, this could be enough to make the entire code thread-safe. Often, it is not.
To demonstrate this, we are going to implement a thread-safe queue object. A queue is a moderately complex data structure, even without thread safety, but, fortunately, we do not need to start from scratch—we have std::queue in the C++ standard library. We can push objects onto the queue and take them from the queue in first-in-first-out order, but only on one thread—it is not safe to push two objects onto the ...