This is a follow-up to Can C++11 condition_variables be used to synchronize processes?.
Can std::condition_variable objects be used as counting semaphores?
Methinks not because the object seems bound to a std::mutex, which implies it can only be used as a binary semaphore. I've looked online, including here, here, and here, but can't find reference or example of using these objects as counting semaphores.
std::condition_variable The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until another thread both modifies a shared variable (the condition), and notifies the condition_variable .
Semaphores are typically used to coordinate access to resources, with the semaphore count initialized to the number of free resources. Threads then atomically increment the count when resources are added and atomically decrement the count when resources are removed.
Yes.
struct counting_sem {
counting_sem(std::ptrdiff_t init=0):count(init) {}
// remove in C++17:
counting_sem(counting_sem&& src) {
auto l = src.lock(); // maybe drop, as src is supposed to be dead
count = src.count;
}
counting_sem& operator=(counting_sem&& src) = delete;
void take( std::size_t N=1 ) {
if (N==0) return;
auto l = lock();
cv.wait(l, [&]{
if (count > 0 && count < (std::ptrdiff_t)N) {
N -= count;
count = 0;
} else if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}
return N == 0;
});
}
void give( std::size_t N=1 ) {
if (N==0) return;
{
auto l = lock();
count += N;
}
cv.notify_all();
}
// reduce the count without waiting for it
void reduce(std::size_t N=1) {
if (N==0) return;
auto l = lock();
count -= N;
}
private:
std::mutex m;
std::condition_variable cv;
std::ptrdiff_t count;
auto lock() {
return std::unique_lock<std::mutex>(m);
}
auto unlocked() {
return std::unique_lock<std::mutex>(m, std::defer_lock_t{});
}
};
Code not tested or compiled, but the design is sound.
take(7)
is not equivalent to for(repeat 7 times) take()
: instead, it takes as much as it can then blocks if that wasn't enough.
Modifying so that it doesn't take anything until there is enough is easy:
if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With