A fixed semaphore

This is a second thread-safe semaphore-oriented design pattern that's more suitable for internal application semaphores that have a fixed number of instances. There is no queue, if a semaphore instance or instances cannot be acquired, too bad.

#include <x/fixed_semaphore.H>

x::fixed_semaphore s=x::fixed_semaphore::create(4);

x::fixed_semaphore::base::acquiredptr acquired=s->acquire(
      []
      {
           return true;
      },
      []
      {
           // ...
      }, 2);

x::fixed_semaphore is a reference-counted object. Its constructor takes the number of available semaphore instances, which defaults to 1.

acquire() immediately returns an x::semaphore::base::acquiredptr. It's null() if the number of available semaphores is fewer than the third, optional parameter, which defaults to 1.

Otherwise, the first functor gets invoked. If it returns false, acquire() returns a null() x::semaphore::base::acquiredptr, and takes no further action.

Otherwise, the requested number of semaphore instances is now considered to be acquired (the fixed semaphore object remains internally locked for the duration of the functor call) and a non-null(), x::semaphore::base::acquiredptr gets returned. This is an opaque, reference-counted, handle the represents the requested number of acquired semaphores.

The handle maintains an internal reference on the semaphore. When the last reference to the handle goes out of scope and it gets destroyed, the second functor that was passed to acquire() gets invoked.

The second functor cannot throw exceptions. When the second functor returns, the acquired semaphore instances are now considered to be released.