The implementation is very short and very dense.
- Here's the implementation of the constructor:
semaphore::semaphore(int value) : value(value), {}
- m and cv are zero-argument constructed.
- Data members are constructed in the order they appear in the class definition (not necessarily the order they appear in the initialization list).
- Here are the implementations of wait and signal, which look like our most recent implementations of waitForPermission and grantPermission:
void semaphore::wait() {
lock_guard<mutex> lg(m);
cv.wait(m, [this]{ return value > 0; });
value--;
}
void semaphore::signal() {
lock_guard<mutex> lg(m);
value++;
if (value == 1) cv.notify_all();
}
- Note that this needs to be captured by the on-the-fly predicate function we pass to cv.wait. We need access to the value data member, and capturing the address of the surrounding object allows this.
- [&value] works with g++, but it's off C++11 specification and won't necessarily work with other compilers.