tf::Semaphore class

class to create a semophore object for building a concurrency constraint

A semaphore creates a constraint that limits the maximum concurrency, i.e., the number of workers, in a set of tasks. You can let a task acquire/release one or multiple semaphores before/after executing its work. A task can acquire and release a semaphore, or just acquire or just release it. A tf::Semaphore object starts with an initial count. As long as that count is above 0, tasks can acquire the semaphore and do their work. If the count is 0 or less, a task trying to acquire the semaphore will not run but goes to a waiting list of that semaphore. When the semaphore is released by another task, it reschedules all tasks on that waiting list.

tf::Executor executor(8);   // create an executor of 8 workers
tf::Taskflow taskflow;

tf::Semaphore semaphore(1); // create a semaphore with initial count 1

for(size_t i=0; i<1000; i++) {
  taskflow.emplace([&](tf::Runtime& rt){ 
    rt.acquire(semaphore);
    std::cout << "critical section here (one worker at any time)\n"; 
    critical_section();
    rt.release(semaphore);
  });
}

executor.run(taskflow).wait();

The above example creates a taskflow of 1000 independent tasks while only one worker will run critical_section at any time due to the semaphore constraint. This arrangement limits the parallelism of critical_section to just one.

Constructors, destructors, conversion operators

Semaphore()
constructs a default semaphore with count equal to zero
Semaphore(size_t count) explicit
constructs a semaphore with the given count

Public functions

auto count(std::memory_order memory_order = std::memory_order_seq_cst) const -> size_t
queries the current value of the associated counter
auto try_acquire() -> bool
tries to atomically decrement the internal counter by 1 if it is greater than 0
void release(size_t n = 1)
atomically increment the internal counter by n
void reset(size_t count, std::memory_order memory_order = std::memory_order_seq_cst)
resets the semaphore to the given count

Function documentation

tf::Semaphore::Semaphore()

constructs a default semaphore with count equal to zero

Application can use tf::Semaphore::reset to reset the counter of the semaphore later.

tf::Semaphore::Semaphore(size_t count) explicit

constructs a semaphore with the given count

A semaphore creates a constraint that limits the maximum concurrency, i.e., the number of workers, in a set of tasks.

tf::Semaphore semaphore(4);  // a semaphore initialized with 4

size_t tf::Semaphore::count(std::memory_order memory_order = std::memory_order_seq_cst) const

queries the current value of the associated counter

Parameters
memory_order the memory order of this load (default std::memory_order_seq_cst)

Queries the current value of the associated counter.

bool tf::Semaphore::try_acquire()

tries to atomically decrement the internal counter by 1 if it is greater than 0

Returns true if it decremented the internal counter, otherwise false

Tries to atomically decrement the internal counter by 1. If the operation succeeds, returns true, otherwise false.

void tf::Semaphore::release(size_t n = 1)

atomically increment the internal counter by n

Parameters
n the value by which the internal counter will be incremented

The release operation always succeeds as it simply increments the counter of this semaphore.

void tf::Semaphore::reset(size_t count, std::memory_order memory_order = std::memory_order_seq_cst)

resets the semaphore to the given count

Parameters
count the new count value
memory_order memory order to which this operation will be applied (default std::memory_order_seq_cst)