StoneThrow StoneThrow - 1 month ago 7
C++ Question

Can std::condition_variables be used as counting semaphores?

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.

Answer

Yes.

struct counting_sem {
  void take( std::size_t N=1 ) {
    if (N==0) return;
    auto l = lock();
    cv.wait(l, [&]{
      while (N != 0 && count > 0) {
        --N; --count;
      }
      return N == 0;
    });
  }
  void give( std::size_t N=1 ) {
    if (N==0) return;
    {
      auto l = lock();
      count += N;
    }
    cv.notify_all();
  }
private:
  std::mutex m;
  std::condition_variable cv;
  std::ptrdiff_t count;

  auto lock() {
    return std::unique_lock<std::mutex>(m);
  }
};

Code not tested or compiled, but the design is sound.

take(7) is equivalent to for(repeat 7 times) take(). It does not take all 7 "atomically". Modifying it to do that is easy:

      if (count >= (std::ptrdiff_t)N) {
        count -= N;
        N = 0;
      }
Comments