C++11 library providing functionality common to all adapters.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

69 lines
2.2 KiB

// This file is under GNU General Public License 3.0
// see LICENSE.txt
#ifndef LIBPEPADAPTER_COUNTING_SEMAPHORE_HH
#define LIBPEPADAPTER_COUNTING_SEMAPHORE_HH
#include <mutex>
#include <condition_variable>
#include <atomic>
namespace pEp {
class CountingSemaphore {
std::mutex mtx;
std::condition_variable cv;
// To synchronize threads, ALWAYS use <atomic> types
std::atomic_uint _count;
public:
CountingSemaphore(unsigned count = 0) : _count(count) {}
// Change the stored count.
CountingSemaphore& operator=(unsigned count)
{
std::unique_lock<std::mutex> lock(mtx);
_count.store (count);
if (count != 0)
cv.notify_one ();
return *this;
}
// Return the current stored count.
unsigned load()
{
return _count.load ();
}
// Atomically decrement the stored count, blocking in case the count
// is currently zero. When the method terminates the counter is
// guaranteed to have been decremented by one unit.
//
// This is Dijkstra's P operation, used to atomically acquire a resource.
void p()
{
std::unique_lock<std::mutex> lock(mtx);
// FIXME: is the loop even needed? Any received notification will
// wake up only one thread, which will see the count as non-zero...
// I guess an if conditional would work just as well as a while
// loop, but I will follow the canonical pattern just in case some
// new bizarre operation other than V is added later.
while (_count.load() == 0)
cv.wait(lock);
_count --;
}
// Atomically increment the stored count. This may wake up one thread
// which is currently executing the p method.
//
// This is Dijkstra's V operation, used to atomically release a resource.
void v()
{
std::unique_lock<std::mutex> lock(mtx);
_count ++;
cv.notify_one();
}
};
} // namespace pEp
#endif // LIBPEPADAPTER_COUNTING_SEMAPHORE_HH