The details are subtle but important.
static mutex forks[kNumForks];
static int numAllowed = kNumForks - 1;
static mutex m;
static condition_variable_any cv;
static void waitForPermission() {
lock_guard<mutex> lg(m);
cv.wait(m, []{ return numAllowed > 0; });
numAllowed--;
}
static void grantPermission() {
lock_guard<mutex> lg(m);
numAllowed++;
if (numAllowed == 1) cv.notify_all();
}
- Because numAllowed is being examined and potentially changed concurrently by many threads, and because a condition framed in terms of it (that is, numAllowed > 0) influences whether a thread blocks or continues uninterrupted, we need a traditional mutex here so that competing threads can lock down exclusive access to all things numAllowed.
- The lock_guard class exists to automate the locking and unlocking of a mutex.
- The lock_guard constructor binds an internal reference to the supplied mutex and calls lock on it (blocking—within the constructor—until the lock can be acquired).
- The lock_guard destructor releases the lock on the same mutex.
- The overall effect—at least in the above two functions—is that the combination of both implementations is marked as one big critical region.
- Java gurus: the lock_guard class is the best thing C++ has in place to emulate Java's synchronized keyword.
- The lock_guard is a template, because its implementation only requires its template type respond to zero-argument lock and unlock methods. The mutex class certainly does that, but many others (e.g. C++11's recursive_mutex, or its timed_mutex) do as well, and the lock_guard didn't want to hard code in mutex.
- condition_variable_any::wait requires a mutex be supplied to help manage its synchronization on the supplied condition.
- If condition_variable_any::wait notices that the supplied condition isn't being met, it puts the current thread to sleep indefinitely and releases the supplied mutex. When the condition_variable_any is notified and a waiting thread is permitted to continue, the thread re-acquires the mutex it released just prior to sleeping.