carb::tasking::ITasking

Defined in carb/tasking/ITasking.h

struct ITasking

Defines a tasking plugin interface, acquired with carb::Framework::acquireInterface() when carb.tasking.plugin is loaded.

ITasking is started automatically on plugin startup. It uses default TaskingDesc, see getDefaultTaskingDesc().

Several ISettings keys exist to provide debug behavior and to override default startup behavior (but do not override a TaskingDesc provided to ITasking::changeParameters()).

Thread Safety

Unless otherwise specified, all functions in this interface can be called from multiple threads simultaneously.

Public Functions

void yieldUntilCounter(RequiredObject counter)

Yields execution to another task until counter reaches its target value.

Tasks invoking this call can resume on different thread. If the task must resume on the same thread, use PinGuard.

Note

deprecated Use wait() instead.

Parameters

counter – The counter to check.

bool timedYieldUntilCounter(RequiredObject counter, uint64_t timeoutNs)

Yields execution to another task until counter reaches its target value or the timeout period elapses.

Tasks invoking this call can resume on different thread. If the task must resume on the same thread, use PinGuard.

Note

Deprecated: Use wait_for() or wait_until() instead.

Parameters
  • counter – The counter to check.

  • timeoutNs – The number of nanoseconds to wait. Pass kInfinite to wait forever or 0 to try immediately without waiting.

Returns

true if the counter period has completed; false if the timeout period elapses.

inline bool checkCounter(Counter *c)

Checks if counter is at the counter’s target value.

Note

Deprecated: The Counter interface is deprecated.

Parameters

c – The counter to check.

Returns

true if the counter is at the target value; false otherwise.

inline uint32_t getCounterValue(Counter *counter)

Retrieves the current value of the target.

Note! Because of the threaded nature of counters, this value may have changed by another thread before the function returns.

Note

Deprecated: The Counter interface is deprecated.

Parameters

counter – The counter.

Returns

The current value of the counter.

inline uint32_t getCounterTarget(Counter *counter)

Gets the target value for the Counter.

Note

Deprecated: The Counter interface is deprecated.

Parameters

counter – The counter to check.

Returns

The target value of the counter.

inline uint32_t fetchAddCounter(Counter *counter, uint32_t value)

Atomically adds a value to the counter and returns the value held previously.

The fetchAdd operation on the counter will be atomic, but this function as a whole is not atomic.

Note

Deprecated: The Counter interface is deprecated.

Parameters
  • counter – The counter.

  • value – The value to add to the counter.

Returns

The value of the counter before the addition.

inline uint32_t fetchSubCounter(Counter *counter, uint32_t value)

Atomically subtracts a value from the counter and returns the value held previously.

The fetchSub operation on the counter will be atomic, but this function as a whole is not atomic.

Note

Deprecated: The Counter interface is deprecated.

Parameters
  • counter – The counter.

  • value – The value to subtract from the counter.

Returns

The value of the counter before the addition.

inline void storeCounter(Counter *counter, uint32_t value)

Atomically replaces the current value with desired on a counter.

The store operation on the counter will be atomic, but this function as a whole is not atomic.

Note

Deprecated: The Counter interface is deprecated.

Parameters
  • counter – The counter.

  • value – The value to load into to the counter.

void lockMutex(Mutex *mutex)

Locks a mutex.

Parameters

mutex – The mutex to lock.

bool waitForTask(TaskContext task)

Blocks the current thread/task until the given Task has completed.

Similar to yieldUntilCounter() but does not require a Counter object.

Note

Deprecated: Use wait() instead.

Parameters

task – The TaskContext to wait on

Returns

true if the wait was successful; false if the TaskContext has already expired or was invalid.

bool try_wait(RequiredObject req)

Checks the object specified in req to see if it is signaled.

Parameters

req – The RequiredObject object to check.

Returns

true if the object is signaled; false if the object is invalid or not signaled.

void wait(RequiredObject req)

Blocks the calling thread or task until req is signaled.

Parameters

req – The RequiredObject object to check.

template<class Rep, class Period>
bool wait_for(std::chrono::duration<Rep, Period> dur, RequiredObject req)

Blocks the calling thread or task until req is signaled or dur has elapsed.

Parameters
  • dur – The duration to wait for.

  • req – The RequiredObject object to check.

Returns

true if the object is signaled; false if the object is invalid or not signaled, or dur elapses.

template<class Clock, class Duration>
bool wait_until(std::chrono::time_point<Clock, Duration> when, RequiredObject req)

Blocks the calling thread or task until req is signaled or the clock reaches when.

Parameters
  • when – The time_point to wait until.

  • req – The RequiredObject object to check.

Returns

true if the object is signaled; false if the object is invalid or not signaled, or when is reached.

void waitSemaphore(Semaphore *sema)

Waits on a semaphore until it has been signaled.

If the semaphore has already been signaled, this function returns immediately.

Parameters

sema – The semaphore to wait on.

void lockSharedMutex(SharedMutex *mutex)

Requests shared access on a SharedMutex object.

Use unlockSharedMutex() to release the shared lock. SharedMutex is not recursive.

Parameters

mutex – The SharedMutex object.

void lockSharedMutexExclusive(SharedMutex *mutex)

Requests exclusive access on a SharedMutex object.

Use unlockSharedMutex() to release the exclusive lock. SharedMutex is not recursive.

Parameters

mutex – The SharedMutex object.

void waitConditionVariable(ConditionVariable *cv, Mutex *m)

Waits on a ConditionVariable object until it is notified.

Prefer using the helper function, waitConditionVariablePred().

The given Mutex must match the Mutex passed in by all other threads/tasks waiting on the ConditionVariable, and must be locked by the current thread/task. While waiting, the Mutex is unlocked. When the thread/task is notified the Mutex is re-locked before returning to the caller. ConditionVariables are allowed to spuriously wake up, so best practice is to check the variable in a loop and sleep if the variable still does not match desired.

Parameters
  • cv – The ConditionVariable to wait on.

  • m – The Mutex that is locked by the current thread/task.

void yieldUntilCounterPinThread(RequiredObject counter)

Yields execution to another task until counter == value.

Task invoking this call will resume on the same thread due to thread pinning. Thread pinning is not efficient. See pinToCurrentThread() for details.

Parameters

counter – The counter to check.

template<class Pred>
inline void waitConditionVariablePred(ConditionVariable *cv, Mutex *m, Pred &&pred)

Checks pred in a loop until it returns true, and waits on a ConditionVariable if pred returns false.

Parameters
  • cv – The ConditionVariable to wait on

  • m – The Mutex associated with the ConditionVariable. Must be locked by the calling thread/task.

  • pred – A function-like predicate object in the form bool(void). waitConditionVariablePred() returns when pred returns true.

template<class Pred>
inline bool timedWaitConditionVariablePred(ConditionVariable *cv, Mutex *m, uint64_t timeoutNs, Pred &&pred)

Checks pred in a loop until it returns true or the timeout period expires, and waits on a ConditionVariable if pred returns false.

Parameters
  • cv – The ConditionVariable to wait on

  • m – The Mutex associated with the ConditionVariable. Must be locked by the calling thread/task.

  • timeoutNs – The relative timeout period in nanoseconds. Specify kInfinite to wait forever or 0 to test immediately without waiting.

  • pred – A function-like predicate object in the form bool(void). waitConditionVariablePred() returns when pred returns true.

Returns

true if the predicate returned true; false if the timeout period expired

template<class Callable, class ...Args>
auto awaitSyncTask(Priority priority, Callable &&f, Args&&... args)

Executes a task synchronously.

Note

To ensure that the task executes in task context, the function is called directly if already in task context. If called from non-task context, f is executed by a call to addTask() but this function does not return until the subtask is complete.

Parameters
  • priority – The priority of the task to execute. Only used if not called in task context.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value.

  • args – Arguments to pass to f.

Returns

The return value of f.

template<class Callable, class ...Args>
auto addTask(Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Runs the given function-like object as a task.

Parameters
  • priority – The priority of the task to execute.

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

inline TaskContext addTask(TaskDesc desc, Counter *counter)

Adds a task to the internal queue.

Note

Deprecated: The other addTask() (and variant) functions accept lambdas and function-like objects, and are designed to simplify adding tasks and add tasks succinctly. Prefer using those functions.

Parameters
  • desc – The TaskDesc describing the task.

  • counter – A counter to associate with this task. It will be incremented by 1. When the task completes, it will be decremented.

Returns

A TaskContext that can be used to refer to this task

template<class Callable, class ...Args>
auto addThrottledTask(Semaphore *throttler, Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Runs the given function-like object as a task when a Semaphore is signaled.

Parameters
  • throttler – (optional) A Semaphore used to throttle the number of tasks that can run concurrently. The task waits until the semaphore is signaled (released) before starting, and then signals the semaphore after the task has executed.

  • priority – The priority of the task to execute.

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

template<class Callable, class ...Args>
auto addSubTask(RequiredObject requiredObject, Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Runs the given function-like object as a task once a Counter reaches its target.

Parameters
  • requiredObject – (optional) An object convertible to RequiredObject (such as a task or Future). that will, upon completing, trigger the execution of this task.

  • priority – The priority of the task to execute.

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

template<class Callable, class ...Args>
auto addThrottledSubTask(RequiredObject requiredObject, Semaphore *throttler, Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Runs the given function-like object as a task once a Counter reaches its target and when a Semaphore is signaled.

Parameters
  • requiredObject – (optional) An object convertible to RequiredObject (such as a task or Future). that will, upon completing, trigger the execution of this task.

  • throttler – (optional) A semaphore used to throttle the number of tasks that can run concurrently. Once requiredObject becomes signaled, the task waits until the semaphore is signaled (released) before starting, and then signals the semaphore after the task has executed.

  • priority – The priority of the task to execute.

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

template<class Callable, class Rep, class Period, class ...Args>
auto addTaskIn(const std::chrono::duration<Rep, Period> &dur, Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Adds a task to occur after a specific duration has passed.

Parameters
  • dur – The duration to wait for. The task is not started until this duration elapses.

  • priority – The priority of the task to execute

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

template<class Callable, class Clock, class Duration, class ...Args>
auto addTaskAt(const std::chrono::time_point<Clock, Duration> &when, Priority priority, Trackers &&trackers, Callable &&f, Args&&... args)

Adds a task to occur at a specific point in time.

Parameters
  • when – The point in time at which to begin the task

  • priority – The priority of the task to execute

  • trackers – (optional) A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value

  • args – Arguments to pass to f

Returns

A Future based on the return type of f

template<class Callable, class ...Args>
void applyRange(size_t range, Callable f, Args&&... args)

Processes a range from [0..range) calling an invocable for each index, potentially from different threads.

See the additional documentation for applyRange.

Note

This function does not return until f has been called (and returned) on every index from [0..range).

Note

Calling this function recursively will automatically scale down the parallelism in order to not overburden the system.

Note

As there is overhead to calling f repeatedly, it is more efficient to use applyRangeBatch() with batchHint = 0 and a f that handles multiple indexes on one invocation.

Warning

Since f can be called from multiple threads simultaneously, all operations it performs must be thread-safe. Additional consideration must be taken since mutable captures of any lambdas or passed in args will be accessed simultaneously by multiple threads so care must be taken to ensure thread safety.

Parameters
  • range – The number of times to call f.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that is repeatedly called until all indexes in [0..range) have been processed, potentially from different threads. It is invoked with parameters f(args..., index) where index is within the range [0..range).

  • args – Arguments to pass to f

template<class Callable, class ...Args>
void applyRangeBatch(size_t range, size_t batchHint, Callable f, Args&&... args)

Processes a range from [0..range) calling an invocable for batches of indexes, potentially from different threads.

See the additional documentation for applyRange.

Note

This function does not return until f has been called (and returned) for every index from [0..range).

Note

Calling this function recursively will automatically scale down the parallelism in order to not overburden the system.

Warning

Since f can be called from multiple threads simultaneously, all operations it performs must be thread-safe. Additional consideration must be taken since mutable captures of any lambdas or passed in args will be accessed simultaneously by multiple threads so care must be taken to ensure thread safety.

Parameters
  • range – The number of times to call f.

  • batchHint – Ignored but retained for API compatibility.

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that is repeatedly called until all indexes in [0..range) have been processed, potentially from different threads. It is invoked with parameters f(args..., startIndex, endIndex) where [startIndex..endIndex) is the range of indexes that must be processed by that invocation of f. Note that endIndex is a past-the-end index and must not actually be processed by an invocation of f. Any return value of f is ignored.

  • args – Arguments to pass to f

template<class T, class Callable, class ...Args>
void parallelFor(T begin, T end, Callable f, Args&&... args)

Processes a range from [begin..end) calling a functor for each index, potentially from different threads.

Note

This function does not return until f has been called (and returned) on every index from [begin.. end)

Note

Calling this function recursively will automatically scale down the parallelism in order to not overburden the system.

Warning

Since f can be called from multiple threads simultaneously, all operations it performs must be thread-safe. Additional consideration must be taken since mutable captures of any lambdas or passed in args will be accessed simultaneously by multiple threads so care must be taken to ensure thread safety.

Parameters
  • begin – The starting value passed to f

  • end – The ending value. Every T(1) step in [begin, end) is passed to f

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value. The index value from [begin..end) is passed as the last parameter (after any passed args).

  • args – Arguments to pass to f

template<class T, class Callable, class ...Args>
void parallelFor(T begin, T end, T step, Callable f, Args&&... args)

Processes a stepped range from [begin..end) calling a functor for each step, potentially from different threads.

Note

This function does not return until f has been called (and returned) on every index from [begin.. end)

Note

Calling this function recursively will automatically scale down the parallelism in order to not overburden the system.

Warning

Since f can be called from multiple threads simultaneously, all operations it performs must be thread-safe. Additional consideration must be taken since mutable captures of any lambdas or passed in args will be accessed simultaneously by multiple threads so care must be taken to ensure thread safety.

Parameters
  • begin – The starting value passed to f

  • end – The ending value. Every step in [begin, end) is passed to f

  • step – The step size to determine every value passed to f

  • f – An invocable object (i.e. functor, lambda, [member] function ptr) that optionally returns a value. The stepped value from [begin..end) is passed as the last parameter (after any passed args).

  • args – Arguments to pass to f

template<class Rep, class Period>
inline void sleep_for(const std::chrono::duration<Rep, Period> &dur)

Causes the current thread or task to sleep for the specified time.

Note

This function is fiber-aware. If currently executing in a fiber, the fiber will be yielded until the requested amount of time has passed. If a thread is currently executing, then the thread will sleep.

Parameters

dur – The duration to sleep for

template<class Clock, class Duration>
inline void sleep_until(const std::chrono::time_point<Clock, Duration> &tp)

Causes the current thread or task to sleep until the specified time.

Note

This function is fiber-aware. If currently executing in a fiber, the fiber will be yielded until the requested amount of time has passed. If a thread is currently executing, then the thread will sleep.

Parameters

tp – The absolute time point to sleep until

template<class T>
inline void futexWait(const std::atomic<T> &val, T compare)

A fiber-safe futex implementation: if val equals compare, the thread or task sleeps until woken.

Warning

Futexes are complicated and error-prone. Prefer using higher-level synchronization primitives.

Parameters
  • val – The atomic value to check.

  • compare – The value to compare against. If val matches this, then the calling thread or task sleeps until futexWakeup() is called.

template<class T, class Rep, class Period>
inline bool futexWaitFor(const std::atomic<T> &val, T compare, std::chrono::duration<Rep, Period> dur)

A fiber-safe futex implementation: if val equals compare, the thread or task sleeps until woken or the timeout period expires.

Warning

Futexes are complicated and error-prone. Prefer using higher-level synchronization primitives.

Parameters
  • val – The atomic value to check.

  • compare – The value to compare against. If val matches this, then the calling thread or task sleeps until futexWakeup() is called.

  • dur – The maximum duration to wait.

Returns

true if val doesn’t match compare or if futexWakeup() was called; false if the timeout period expires.

template<class T, class Clock, class Duration>
inline bool futexWaitUntil(const std::atomic<T> &val, T compare, std::chrono::time_point<Clock, Duration> when)

A fiber-safe futex implementation: if val equals compare, the thread or task sleeps until woken or the specific time is reached.

Warning

Futexes are complicated and error-prone. Prefer using higher-level synchronization primitives.

Parameters
  • val – The atomic value to check.

  • compare – The value to compare against. If val matches this, then the calling thread or task sleeps until futexWakeup() is called.

  • when – The clock time to wait until.

Returns

true if val doesn’t match compare or if futexWakeup() was called; false if the clock time is reached.

template<class T>
inline unsigned futexWakeup(const std::atomic<T> &val, unsigned count)

Wakes threads or tasks waiting in futexWait(), futexWaitFor() or futexWaitUntil().

Warning

Futexes are complicated and error-prone. Prefer using higher-level synchronization primitives.

Parameters
  • val – The same val passed to futexWait(), futexWaitFor() or futexWaitUntil().

  • count – The number of threads or tasks to wakeup. To wake all waiters use UINT_MAX.

Returns

The number of threads or tasks that were waiting and are now woken.

void bindTrackers(RequiredObject requiredObject, Trackers &&trackers)

Binds any number of Tracker objects to the given RequiredObject.

Effectively allows adding trackers to a given object.

Previously this was only achievable through a temporary task:

// Old way: a task that would bind `taskGroup` to `requiredObject`
tasking->addSubTask(requiredObject, Priority::eDefault, { taskGroup }, []{});
// New way: direct binding:
tasking->bindTrackers(requiredObject, { taskGroup });
The previous method wasted time in that one of the task threads would eventually have to pop the task from the queue and run an empty function. Calling bindTrackers() does not waste this time.

However, there are some “disadvantages.” The addSubTask() method would allocate a TaskContext, return a Future, and could be canceled. These features were seldom needed, hence this function.

Parameters
  • requiredObject – An object convertible to RequiredObject (such as a task or Future). The given trackers will be bound to this required object.

  • trackers – A std::initializer_list of zero or more Tracker objects. Note that this must be a temporary object. The Tracker objects can be used to determine task completion or to provide input/output parameters to the task system.

template<class T, std::enable_if_t<std::is_convertible<T, const char*>::value, bool> = false>
inline void nameTask(TaskContext task, T &&name)

Sets a name for a task for debugging purposes, similar to how threads can be named.

This function is optimized for a literal string: passing a literal string as name does not copy the string but instead retains the pointer as it is guaranteed to never change. Passing a non-literal string will result in a copy.

The task name is visible in the debugger as debug information for a task.

Retrieving the task name can be accomplished through getTaskDebugInfo().

Thread Safety

It is safe to set a task name from multiple threads, though inadvisable. Reading the task name via getTaskDebugInfo() while it is being changed in a different thread is not strongly ordered and may result in an empty string being read, or random bytes as the name string, but will not result in a crash.

Note

It is often easier to name the task as it’s created by passing a task name as a Tracker object to addTask() or the other task creation functions.

Template Parameters

T – A type that is convertible to const char*. See name below.

Parameters
  • task – The TaskContext to name. If this is not a valid task, or the task has already completed or has been cancelled, nothing happens.

  • name – Either a const char* (dynamic string) or a const char (&)[N] (literal string) as the string name. May be nullptr to un-set a task name. Dynamic strings will be copied before the call returns. Literal strings will be retained by pointer value.

Public Members

void (*changeParameters)(TaskingDesc desc)

Changes the parameters under which the ITasking interface functions.

This may stop and start threads, but will not lose any tasks in progress or queued.

Thread Safety

It is unsafe to add any additional tasks while calling this function. The caller must ensure that no new tasks are added until this function returns.

Note

This function reloads all registered IFiberEvents interfaces so they will start receiving notifications. However, if this is the only change desired it is recommended to use reloadFiberEvents() instead.

Warning

Calling this function from within a task context causes undefined behavior.

Param desc

The tasking plugin descriptor.

const TaskingDesc &(*getDesc)()

Get TaskingDesc the plugin currently running with.

Return

The tasking plugin descriptor.

Counter *(*createCounter)()

Creates a Counter with target value of zero.

Warning

Prefer using CounterWrapper instead.

Return

The counter created.

Counter *(*createCounterWithTarget)(uint32_t target)

Creates a counter with a specific target value.

Warning

Prefer using CounterWrapper instead.

Param target

The target value of the counter. Yielding on this counter will wait for this target.

Return

The counter created.

void (*destroyCounter)(Counter *counter)

Destroys the counter.

Param counter

A counter.

void (*addTasks)(TaskDesc *tasks, size_t taskCount, Counter *counter)

Adds a group of tasks to the internal queue.

Param tasks

The tasks to queue.

Param taskCount

The number of tasks.

Param counter

A counter to associate with the task group as a whole. Initially it incremented by taskCount. When each task completes, it will be decremented by 1.

void (*yield)()

Yields execution.

Task invoking this call will be put in the very end of task queue, priority is ignored.

bool (*pinToCurrentThread)()

Causes the currently executing TaskContext to be “pinned” to the thread it is currently running on.

This function causes the current thread to be the only task thread that can run the current task. This is necessary in some cases where thread specificity is required (those these situations are NOT recommended for tasks): holding a mutex, or using thread-specific data, etc. Thread pinning is not efficient (the pinned thread could be running a different task causing delays for the current task to be resumed, and wakeTask() must wait to return until the pinned thread has been notified) and should therefore be avoided.

Call unpinFromCurrentThread() to remove the pin, allowing the task to run on any thread.

Warning

Do not call this function directly; instead use PinGuard.

Note

All calls to pin a thread will issue a warning log message.

Note

It is assumed that the task is allowed to move to another thread during the pinning process, though this may not always be the case. Only after pinToCurrentThread() returns will a task be pinned. Therefore, make sure to call pinToCurrentThread() before any operation that requires pinning.

Return

true if the task was already pinned; false if the task was not pinned or if not called from Task Context (i.e. getTaskContext() would return kInvalidTaskContext)

bool (*unpinFromCurrentThread)()

Un-pins the currently executing TaskContext from the thread it is currently running on.

Warning

Do not call this function directly; instead use PinGuard.

Return

true if the task was successfully un-pinned; false if the task was not pinned or if not called from Task Context (i.e. getTaskContext() would return kInvalidTaskContext)

Mutex *(*createMutex)()

Creates a non-recursive mutex.

Note

Both createMutex() and createRecursiveMutex() return a Mutex object; it is up to the creator to ensure that the Mutex object is used properly. A Mutex created with createMutex() will call std::terminate() if recursively locked.

Warning

Prefer using MutexWrapper instead.

Return

The created non-recursive mutex.

void (*destroyMutex)(Mutex *mutex)

Destroys a mutex.

Param The

mutex to destroy.

bool (*timedLockMutex)(Mutex *mutex, uint64_t timeoutNs)

Locks a mutex or waits for the timeout period to expire.

Note

Attempting to recursively lock a mutex created with createMutex() will abort. Use a mutex created with createRecursiveMutex() to support recursive locking.

Param mutex

The mutex to lock.

Param timeoutNs

The relative timeout in nanoseconds. Specify kInfinite to wait forever or 0 to try locking without waiting.

Return

true if the calling thread/fiber now has ownership of the mutex; false if the timeout period expired.

void (*unlockMutex)(Mutex *mutex)

Unlock a mutex.

Param The

mutex to unlock.

void (*sleepNs)(uint64_t nanoseconds)

Sleeps for the given number of nanoseconds.

Prefer using sleep_for() or sleep_until()

Note

This function is fiber-aware. If currently executing in a fiber, the fiber will be yielded until the requested amount of time has passed. If a thread is currently executing, then the thread will sleep.

Param nanoseconds

The amount of time to yield/sleep, in nanoseconds.

TaskContext (*getTaskContext)()

If the calling thread is running in “task context”, that is, a fiber executing a task previously queued with addTask(), this function returns a handle that can be used with suspendTask() and wakeTask().

Return

kInvalidTaskContext if the calling thread is not running within “task context”; otherwise, a TaskContext handle is returned that can be used with suspendTask() and wakeTask(), as well as anywhere a RequiredObject is used.

bool (*suspendTask)()

Suspends the current task.

Does not return until wakeTask() is called with the task’s TaskContext (see getTaskContext()).

Note

to avoid race-conditions between wakeTask() and suspendTask(), a wakeTask() that occurs before suspendTask() has been called will cause suspendTask() to return true immediately without waiting.

Return

true when wakeTask() is called. If the current thread is not running in “task context” (i.e. getTaskContext() would return kInvalidTaskContext), then this function returns false immediately.

bool (*wakeTask)(TaskContext task)

Wakes a task previously suspended with suspendTask().

wakeTask() cannot be called on the current task context (false will be returned). Additional situations that will log (as a warning) and return false:

  • The task context given already has a pending wake

  • The task has finished

  • The task context given is sleeping or otherwise waiting on an event (cannot be woken)

  • The given TaskContext is not valid

Note

to avoid race-conditions between wakeTask() and suspendTask(), a wakeTask() that occurs before suspendTask() has been called will cause suspendTask() to return true immediately without waiting. The wakeTask() function returns immediately and does not wait for the suspended task to resume.

Param task

The TaskContext (returned by getTaskContext()) for the task suspended with suspendTask().

Return

true if the task was woken properly. false if a situation listed above occurs.

Semaphore *(*createSemaphore)(unsigned value)

Creates a fiber-aware semaphore primitive.

A semaphore is a gate that lets a certain number of tasks/threads through. This can also be used to throttle tasks (see addThrottledTask()). When the count of a semaphore goes negative tasks/threads will wait on the semaphore.

Note

Semaphore can be used for Throttling tasks.

Warning

Prefer using SemaphoreWrapper instead.

Param value

The starting value of the semaphore. Limited to INT_MAX. 0 means that any attempt to wait on the semaphore will block until the semaphore is released.

Return

A Semaphore object. When finished, dispose of the semaphore with destroySemaphore().

void (*destroySemaphore)(Semaphore *sema)

Destroys a semaphore object created by createSemaphore()

Param sema

The semaphore to destroy.

void (*releaseSemaphore)(Semaphore *sema, unsigned count)

Releases (or posts, or signals) a semaphore.

If a task/thread is waiting on the semaphore when it is released, the task/thread is un-blocked and will be resumed. If no tasks/threads are waiting on the semaphore, the next task/thread that attempts to wait will resume immediately.

Param sema

The semaphore to release.

Param count

The number of tasks/threads to release.

bool (*timedWaitSemaphore)(Semaphore *sema, uint64_t timeoutNs)

Waits on a semaphore until it has been signaled or the timeout period expires.

If the semaphore has already been signaled, this function returns immediately.

Param sema

The semaphore to wait on.

Param timeoutNs

The relative timeout period in nanoseconds. Specify kInfinite to wait forever, or 0 to test immediately without waiting.

Return

true if the semaphore count was decremented; false if the timeout period expired.

SharedMutex *(*createSharedMutex)()

Creates a fiber-aware SharedMutex primitive.

A SharedMutex (also known as a read/write mutex) allows either multiple threads/tasks to share the primitive, or a single thread/task to own the primitive exclusively. Threads/tasks that request ownership of the primitive, whether shared or exclusive, will be blocked until they can be granted the access level requested. SharedMutex gives priority to exclusive access, but will not block additional shared access requests when exclusive access is requested.

Warning

Prefer using SharedMutexWrapper instead.

Return

A SharedMutex object. When finished, dispose of the SharedMutex with destroySharedMutex().

bool (*timedLockSharedMutex)(SharedMutex *mutex, uint64_t timeoutNs)

Requests shared access on a SharedMutex object with a timeout period.

Use unlockSharedMutex() to release the shared lock. SharedMutex is not recursive.

Param mutex

The SharedMutex object.

Param timeoutNs

The relative timeout period in nanoseconds. Specify kInfinite to wait forever or 0 to test immediately without waiting.

Return

true if the shared lock succeeded; false if timed out.

bool (*timedLockSharedMutexExclusive)(SharedMutex *mutex, uint64_t timeoutNs)

Requests exclusive access on a SharedMutex object with a timeout period.

Use unlockSharedMutex() to release the exclusive lock. SharedMutex is not recursive.

Param mutex

The SharedMutex object.

Param timeoutNs

The relative timeout period in nanoseconds. Specify kInfinite to wait forever or 0 to test immediately without waiting.

Return

true if the exclusive lock succeeded; false if timed out.

void (*unlockSharedMutex)(SharedMutex *mutex)

Releases a shared or an exclusive lock on a SharedMutex object.

Param mutex

The SharedMutex object.

void (*destroySharedMutex)(SharedMutex *mutex)

Destroys a SharedMutex previously created with createSharedMutex().

Param mutex

The SharedMutex object to destroy.

ConditionVariable *(*createConditionVariable)()

Creates a fiber-aware ConditionVariable primitive.

ConditionVariable is a synchronization primitive that, together with a Mutex, blocks one or more threads or tasks until a condition becomes true.

Warning

Prefer using ConditionVariableWrapper instead.

Return

The ConditionVariable object. Destroy with destroyConditionVariable() when finished.

void (*destroyConditionVariable)(ConditionVariable *cv)

Destroys a previously-created ConditionVariable object.

Param cv

The ConditionVariable to destroy

bool (*timedWaitConditionVariable)(ConditionVariable *cv, Mutex *m, uint64_t timeoutNs)

Waits on a ConditionVariable object until it is notified or the timeout period expires.

Prefer using the helper function, timedWaitConditionVariablePred().

The given Mutex must match the Mutex passed in by all other threads/tasks waiting on the ConditionVariable, and must be locked by the current thread/task. While waiting, the Mutex is unlocked. When the thread/task is notified the Mutex is re-locked before returning to the caller. ConditionVariables are allowed to spuriously wake up, so best practice is to check the variable in a loop and sleep if the variable still does not match desired.

Param cv

The ConditionVariable to wait on.

Param m

The Mutex that is locked by the current thread/task.

Param timeoutNs

The relative timeout period in nanoseconds. Specify kInfinite to wait forever or 0 to test immediately without waiting.

Return

true if the condition variable was notified; false if the timeout period expired.

void (*notifyConditionVariableOne)(ConditionVariable *cv)

Wakes one thread/task currently waiting on the ConditionVariable.

Note

Having the Mutex provided to waitConditionVariable() locked while calling this function is recommended but not required.

Param cv

The condition variable to notify

void (*notifyConditionVariableAll)(ConditionVariable *cv)

Wakes all threads/tasks currently waiting on the ConditionVariable.

Note

Having the Mutex provided to waitConditionVariable() locked while calling this function is recommended but not required.

Param cv

The condition variable to notify

bool (*changeTaskPriority)(TaskContext ctx, Priority newPrio)

Changes a tasks priority.

Note

This can be used to change a task to execute on the main thread when it next resumes when using Priority::eMain. If called from within the context of the running task, the task immediately suspends itself until resumed on the main thread with the next call to executeMainTasks(), at which point this function will return.

Param ctx

The TaskContext returned by getTaskContext() or Future::task_if().

Param newPrio

The Priority to change the task to.

Return

true if the priority change took effect; false if the TaskContext is invalid.

void (*executeMainTasks)()

Executes all tasks that have been queued with Priority::eMain until they finish or yield.

Note

Scheduled tasks (addTaskIn() / addTaskAt()) with Priority::eMain will only be executed during the next executeMainTasks() call after the requisite time has elapsed.

Mutex *(*createRecursiveMutex)()

Creates a recursive mutex.

Note

Both createMutex() and createRecursiveMutex() return a Mutex object; it is up to the creator to ensure that the Mutex object is used properly. A Mutex created with createMutex() will call std::terminate() if recursively locked.

Warning

Prefer using RecursiveMutexWrapper instead.

Return

The created recursive mutex.

bool (*tryCancelTask)(TaskContext task)

Attempts to cancel an outstanding task.

If the task has already been started, has already been canceled or has completed, false is returned.

If true is returned, then the task is guaranteed to never start, but every other side effect is as if the task completed. That is, any Counter objects that were passed to addTask() will be decremented; any blocking calls to waitForTask() will return true. The Future object for this task will no longer wait, but any attempt to read a non-void value from it will call std::terminate(). If the addTask() call provided a TaskDesc::cancel member, it will be called in the context of the calling thread and will finish before tryCancelTask() returns true.

Param task

The TaskContext returned by getTaskContext() or Future::task_if().

Return

true if the task was successfully canceled and state reset as described above. false if the task has cannot be canceled because it has already started, already been canceled or has already finished.

TaskStorageKey (*allocTaskStorage)(TaskStorageDestructorFn fn)

Attempts to allocate task storage, which is similar to thread-local storage but specific to a task.

Allocates a “key” for Task Storage. A value can be stored at this key location (“slot”) that is specific to each task. When the task finishes, fn is executed for any non-nullptr value stored in that slot.

Values can be stored in the Task Storage slot with setTaskStorage() and getTaskStorage().

When Task Storage is no longer needed, use freeTaskStorage() to return the slot to the system.

Warning

The number of slots are very limited. If no slots are available, kInvalidTaskStorageKey is returned.

Param fn

(Optional) A destructor function called when a task finishes with a non-nullptr value in the allocated slot. The value stored with setTaskStorage() is passed to the destructor. If a destructor is not desired, nullptr can be passed.

Return

An opaque TaskStorageKey representing the slot for the requested Task Storage data. If no slots are available, kInvalidTaskStorageKey is returned.

void (*freeTaskStorage)(TaskStorageKey key)

Frees a Task Storage slot.

Note

Any associated destructor function registered with allocTaskStorage() will not be called for any data present in currently running tasks. Once freeTaskStorage() returns, the destructor function registered with allocTaskStorage() will not be called for any data on any tasks.

Param key

The Task Storage key previously allocated with allocTaskStorage().

bool (*setTaskStorage)(TaskStorageKey key, void *value)

Stores a value at a slot in Task Storage for the current task.

The destructor function passed to allocTaskStorage() will be called with any non-nullptr values remaining in Task Storage at the associated key when the task finishes.

Warning

This function can only be called from task context, otherwise false is returned.

Param key

The Task Storage key previously allocated with allocTaskStorage().

Param value

A value to store at the Task Storage slot described by key for the current task only.

Return

true if the value was stored; false otherwise.

void *(*getTaskStorage)(TaskStorageKey key)

Retrieves a value at a slot in Task Storage for the current task.

The destructor function passed to allocTaskStorage() will be called with any non-nullptr values remaining in Task Storage at the associated key when the task finishes.

Warning

This function can only be called from task context, otherwise nullptr is returned.

Param key

The Task Storage key previously allocated with allocTaskStorage().

Return

The value previously passed to setTaskStorage(), or nullptr if not running in task context or a value was not previously passed to setTaskStorage() for the current task.

bool (*getTaskDebugInfo)(TaskContext task, TaskDebugInfo *out)

Retrieves debug information about a specific task.

Note

This information is intended for debug only and should not affect application state or decisions in the application.

Warning

Since carb.tasking is an inherently multi-threaded API, the values presented as task debug information may have changed in a worker thread in the short amount of time between when they were generated and when they were read by the application. As such, the debug information was true at a previous point in time and should not be considered necessarily up-to-date.

Param task

The TaskContext to retrieve information about.

Param out

[out] A structure to fill with debug information about task. The TaskDebugInfo::sizeOf field must be pre-filled by the caller. May be nullptr to determine if task is valid.

Return

true if the TaskContext was valid and out (if non-nullptr) was filled with known information about task. false if out specified an unknown size or task does not refer to a valid task.

bool (*walkTaskDebugInfo)(TaskDebugInfo &info, TaskDebugInfoFn fn, void *context)

Walks all current tasks and calls a callback function with debug info for each.

Note

This information is intended for debug only and should not affect application state or decisions in the application.

Warning

Since carb.tasking is an inherently multi-threaded API, the values presented as task debug information may have changed in a worker thread in the short amount of time between when they were generated and when they were read by the application. As such, the debug information was true at a previous point in time and should not be considered necessarily up-to-date.

Param info

A structure to fill with debug information about tasks encountered during the walk. The TaskDebugInfo::sizeOf field must be pre-filled by the caller.

Param fn

A function to call for each task encountered. The function is called repeatedly with a different task each time, until all tasks have been visited or the callback function returns false.

Param context

Application-specific context information that is passed directly to each invocation of fn.

void (*reloadFiberEvents)()

Instructs ITasking to reload all IFiberEvents interfaces.

The IFiberEvents interface is used by ITasking to notify listeners that are interested in fiber-switch events. All IFiberEvents interfaces are queried from the carb::Framework by ITasking only at startup, or when changeParameters() is called, or when reloadFiberEvents() is called.

Unlike changeParameters(), this function is safe to call from within a task, or from multiple threads simultaneously, and tasks can be added while this function is executing.

Note

This function is a task system synchronization point, requiring all task threads to synchronize and pause before reloading IFiberEvents interfaces. Generally this happens rapidly, but if a task thread is busy, the entire tasking system will wait for the task to finish or enter a wait state before reloading IFiberEvents interfaces.

Public Static Functions

static inline constexpr carb::InterfaceDesc getInterfaceDesc() noexcept

Returns information about this interface.

Auto-generated by CARB_PLUGIN_INTERFACE() or CARB_PLUGIN_INTERFACE_EX.

Returns

The carb::InterfaceDesc struct with information about this interface.

static inline constexpr carb::InterfaceDesc getLatestInterfaceDesc() noexcept

Returns information about the latest version of this interface.

Auto-generated by CARB_PLUGIN_INTERFACE() or CARB_PLUGIN_INTERFACE_EX.

Returns

The carb::InterfaceDesc struct with information about the latest version of this interface.