diff --git a/SimoxUtility/threads/CountingSemaphore.cpp b/SimoxUtility/threads/CountingSemaphore.cpp index 9e6687e62c9900e841dc2f6b73dd9fe50b5b8812..2f6e616dda67661925905c85d95b47d2312975fb 100644 --- a/SimoxUtility/threads/CountingSemaphore.cpp +++ b/SimoxUtility/threads/CountingSemaphore.cpp @@ -7,14 +7,22 @@ namespace simox::threads CountingSemaphore::CountingSemaphore() {} - CountingSemaphore::CountingSemaphore(unsigned int count) : _count(count) + CountingSemaphore::CountingSemaphore(unsigned int count) : + _count(count) + {} + + CountingSemaphore::CountingSemaphore(unsigned int count, unsigned int maxCount) : + _count(count), _maxCount(maxCount) {} void CountingSemaphore::notify() { std::lock_guard<std::mutex> lock(_mutex); - ++_count; + if (!_maxCount || _count < *_maxCount) + { + ++_count; + } _condition.notify_one(); } diff --git a/SimoxUtility/threads/CountingSemaphore.h b/SimoxUtility/threads/CountingSemaphore.h index a7bc78f9059c7584b0f3cda781ca487e8d2ad726..e784b6b6737816148605bfb9bf7103c317e3f534 100644 --- a/SimoxUtility/threads/CountingSemaphore.h +++ b/SimoxUtility/threads/CountingSemaphore.h @@ -2,6 +2,7 @@ #include <condition_variable> #include <mutex> +#include <optional> namespace simox::threads @@ -14,33 +15,52 @@ namespace simox::threads * 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. + * An optional max count can limit the value of count (useful e.g. when your + * buffer has a limited number of items). * - * Can be used e.g. in a Producer-Consumer pattern. - * The producer signals new jobs via `notify()`, while the consumer waits + * A counting semaphore can be used e.g. in Producer-Consumer patterns. + * The producer signals new jobs/items via `notify()`, while the consumer waits * for new jobs via `wait()`. */ class CountingSemaphore { public: - /// Construct an initially blocking semaphore (initial count 0). + /// Construct an initially blocking semaphore (initial count 0) without max count. CountingSemaphore(); - /// Construct a semaphore with the given count. + /** + * @brief Construct a semaphore with the given initial count without max count. + * @param count The initial count (0 to block initially). + */ CountingSemaphore(unsigned int count); + /** + * @brief Construct a semaphore with the given initial count and max count. + * @param count The initial count (0 to block initially). + * @param maxCount An optional count limit (1 for a binary semaphore). + */ + CountingSemaphore(unsigned int count, unsigned int maxCount); /** * @brief Signal that one waiting thread may continue. + * * Also known as `post()` or `signal()`. + * Increments the count by 1, if it is below the optional max count. */ void notify(); /** * @brief Wait until a thread may enter. + * + * Decrements the count when resuming. */ void wait(); /** - * @brief Try to enter. If the semaphore is currently blocking, return false. + * @brief Try to enter. + * + * If the semaphore is currently blocking, return false. + * If the semaphore is free (count > 0), decrement the count and return true. + * * @return True if entering was successful, false if semaphore was blocking. */ bool try_wait(); @@ -56,6 +76,9 @@ namespace simox::threads /// The current count. Waiting threads may enter when > 0. unsigned int _count = 0; + /// An optional maximal count. All `notifiy()`s increasing the counter above maxCount are ignored. + std::optional<unsigned int> _maxCount = std::nullopt; + }; }