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;
+
     };
 
 }