permits model is a counter for which there is \(n\) threads can do a task. For instance, there is \(n\) permits; each time it is requested, it needs to be subtracted.
Ideally, we do this without busy waiting (while loops with lock and unlocks). So:
condition variable
you can call wait on a condition variable, which will block until another thread calls notify_all.
- identify a single event to wait/notify
- ensure that there is something to check to represent the event
- create a condition variable and share it
- identify who is the notifier, call notify_all when appropriate
- identify who will wait, and wait until condition variable triggers
condition_variable_any permitsCV;
// ...
thread(ref(permitsCV))
Identify the ISOLATED event to notify: for instance, whenever permit goes from 0=>1, you notify. But, when permits go from 1=>2, there really isn’t really a need to notify. If you gave wait an unlocked lock, you UB.
But, implementing this is a little tricky: before sleeping on the condition variable, we have to release the underlying lock, but then values are not guaranteed after you unlock. So, the actual implementation:
permits.lock();
while (permits == 0) {
permitsCV.wait(permitsLock);
}
permits--;
permitsLock.unlock();
the condition variable will…
- start sleeping FIRST
- unlock a lock FOR US AFTER the sleeping starts
- after waiting ends, tries to reaquire lock
- blocks until we have the lock again
this ensures that you don’t have to give up the lock before sleeping.
We need a “while” loop here to CHECK whether or not, after sleeping is over, our locked variable needs to be checked again just in case another thread took it: just because we woke up it doesn’t mean the condition is true forever.
We also need a “while” loop because condition variables will send false wakeup signal, so we need to check the condition to be extra sure.
so CALL CONDITION VARIABLES IN A WHILE LOOP.
implementation
similar to mutexs
wait
- should autonomically put the thread to sleep + unlock the given lock
- when the thread wakes up, it should reacquire the lock + return
notify one/all
- notify_one: should wake up + unblock first waiting thread
- notify_all: should wake up/unblock all waiting threads
if no one is waiting, do nothing.