diff --git a/SimoxUtility/CMakeLists.txt b/SimoxUtility/CMakeLists.txt index 02e16fe9dcf44ab1d8452047f998e4aa9c10b89a..2745556a2d74708f200d3b2cc9dd4902a10b178a 100644 --- a/SimoxUtility/CMakeLists.txt +++ b/SimoxUtility/CMakeLists.txt @@ -88,6 +88,7 @@ SET(SOURCES shapes/json_conversions.cpp threads/system_thread_id.cpp + threads/CountingSemaphore.cpp ) SET(INCLUDES @@ -256,6 +257,7 @@ SET(INCLUDES backport/span/gcc_header.h threads/system_thread_id.h + threads/CountingSemaphore.h ) simox_generate_subdir_headers( diff --git a/SimoxUtility/threads.h b/SimoxUtility/threads.h index cd685bff07eeb0cd366b4c6f4390d714c20494c9..7c9962102a968d6bf46aa18e66aed4895df62c51 100644 --- a/SimoxUtility/threads.h +++ b/SimoxUtility/threads.h @@ -2,4 +2,5 @@ // This file is generated! +#include "threads/CountingSemaphore.h" #include "threads/system_thread_id.h" diff --git a/SimoxUtility/threads/CountingSemaphore.cpp b/SimoxUtility/threads/CountingSemaphore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e6687e62c9900e841dc2f6b73dd9fe50b5b8812 --- /dev/null +++ b/SimoxUtility/threads/CountingSemaphore.cpp @@ -0,0 +1,42 @@ +#include "CountingSemaphore.h" + + +namespace simox::threads +{ + + CountingSemaphore::CountingSemaphore() + {} + + CountingSemaphore::CountingSemaphore(unsigned int count) : _count(count) + {} + + + void CountingSemaphore::notify() + { + std::lock_guard<std::mutex> lock(_mutex); + ++_count; + _condition.notify_one(); + } + + void CountingSemaphore::wait() + { + std::unique_lock<std::mutex> lock(_mutex); + _condition.wait(lock, [this]() + { + return _count > 0; + }); + --_count; + } + + bool CountingSemaphore::try_wait() + { + std::unique_lock<std::mutex> lock(_mutex); + if (_count > 0) + { + --_count; + return true; + } + return false; + } + +} diff --git a/SimoxUtility/threads/CountingSemaphore.h b/SimoxUtility/threads/CountingSemaphore.h new file mode 100644 index 0000000000000000000000000000000000000000..a7bc78f9059c7584b0f3cda781ca487e8d2ad726 --- /dev/null +++ b/SimoxUtility/threads/CountingSemaphore.h @@ -0,0 +1,61 @@ +#pragma once + +#include <condition_variable> +#include <mutex> + + +namespace simox::threads +{ + + /** + * @brief A counting semaphore. + * + * Threads can enter when the internal count is > 0. + * Notifiying the semaphore increments the count and allows threads to enter. + * A thread can wait until it may enter. When it enters, it decrements + * the internal count. + * + * Can be used e.g. in a Producer-Consumer pattern. + * The producer signals new jobs via `notify()`, while the consumer waits + * for new jobs via `wait()`. + */ + class CountingSemaphore + { + public: + + /// Construct an initially blocking semaphore (initial count 0). + CountingSemaphore(); + /// Construct a semaphore with the given count. + CountingSemaphore(unsigned int count); + + /** + * @brief Signal that one waiting thread may continue. + * Also known as `post()` or `signal()`. + */ + void notify(); + + /** + * @brief Wait until a thread may enter. + */ + void wait(); + + /** + * @brief Try to enter. If the semaphore is currently blocking, return false. + * @return True if entering was successful, false if semaphore was blocking. + */ + bool try_wait(); + + + private: + + /// The mutex for _condition and _count. + std::mutex _mutex; + /// The condition variable to wake up waking threads. + std::condition_variable _condition; + + /// The current count. Waiting threads may enter when > 0. + unsigned int _count = 0; + + }; + +}