Squid::Tasks 1.0.0
C++14 coroutine-based task library for games
Task< tRet, RefType, Resumable > Class Template Reference

#include <Task.h>

Public Member Functions

 Task ()
 Default constructor (constructs an invalid handle)
 
 Task (nullptr_t)
 Null-pointer constructor (constructs an invalid handle)
 
 Task (const Task &in_otherTask)
 Copy constructor (TaskHandle/WeakTaskHandle only)
 
 Task (Task &&in_otherTask) noexcept
 Move constructor.
 
Taskoperator= (nullptr_t) noexcept
 Null-pointer assignment operator (makes the handle invalid)
 
Taskoperator= (const Task &in_otherTask)
 Copy assignment operator (TaskHandle/WeakTaskHandle only)
 
Taskoperator= (Task &&in_otherTask) noexcept
 Move assignment operator.
 
 ~Task ()
 Destructor.
 
bool IsValid () const
 Returns whether the underlying coroutine is valid.
 
 operator bool () const
 Conversion-to-bool that yields whether an underlying coroutine is set for the task.
 
bool IsDone () const
 Returns whether the task has terminated.
 
bool IsStopRequested () const
 Returns whether a stop request has been issued for the task.
 
void RequestStop ()
 Issues a request for the task to terminate gracefully as soon as possible.
 
void Kill ()
 Immediately terminates the task.
 
template<typename U = tRet, typename std::enable_if_t<!std::is_void< U >::value > * = nullptr>
std::optional< tRet > TakeReturnValue ()
 Attempts to take the task's return value (throws error if return value is either orphaned or was already taken)
 
eTaskStatus Resume ()
 Resumes the task (Task/WeakTask only)
 
std::string GetDebugName (std::optional< TaskDebugStackFormatter > in_formatter={}) const
 Gets this task's debug name (use TASK_NAME to set the debug name)
 
std::string GetDebugStack (std::optional< TaskDebugStackFormatter > in_formatter={}) const
 Gets this task's debug stack (use TASK_NAME to set a task's debug name)
 
auto CancelIf (tTaskCancelFn in_cancelFn) &&
 
auto CancelIfStopRequested () &&
 
auto StopIf (tTaskCancelFn in_cancelFn) &&
 Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (without timeout). More...
 
auto StopIf (tTaskCancelFn in_cancelFn, tTaskTime in_timeout) &&
 Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (with timeout in the global time-stream). More...
 
template<typename tTimeFn >
auto StopIf (tTaskCancelFn in_cancelFn, tTaskTime in_timeout, tTimeFn in_timeFn) &&
 Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (with timeout in a given time-stream). More...
 

Detailed Description

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
class Task< tRet, RefType, Resumable >

Task is a high-level task handle used to manage the lifetime and execution of an underlying coroutine

Handle Types

The Task class is actually a template class that implements 4 user-level handle types:

  • Task<tRet>
    • A resumable task handle that holds a strong reference to the underlying coroutine.
    • Should be the return type of every coroutine you write.
    • Can be used to resume tasks, kill tasks, check if they are done, and access a return value.
    • Is permitted to have void return type (e.g. Task<>), which disables return value access.
  • WeakTask
    • A resumable task handle that holds a weak reference to the underlying coroutine.
    • Can only be used to resume tasks, kill tasks, and check if they are done.
  • TaskHandle<tRet>
    • A non-resumable task handle that holds a strong reference to the underlying coroutine.
    • Can be used to kill tasks, check if they are done, and access a return value.
    • Is permitted to have void return type (e.g. TaskHandle<>), which disables return value access.
  • WeakTaskHandle
    • A non-resumable task handle that holds a weak reference to the underlying coroutine.
    • Can only be used to kill tasks and check if they are done.
Handle Type Return Type Resumable? Ref Strength
Task <any type> Yes Strong
WeakTask void Yes Weak
TaskHandle <any type> No Strong
WeakTaskHandle void No Weak

Conversion Rules

It is possible to convert between these 4 types, but not all conversions are permitted. The rules for conversion are:

In simpler terms, this means: a handle can always convert to a handle type with fewer capabilities, but not vice-versa.

Generally-speaking, it would be unsafe to convert in such a way that would add handle properties, hence the motivation for these conversion rules. Care has been taken, however, to provide clear human-readable compile-time error messages if and when an invalid conversion is attempted in code.

Resumability

For a given coroutine instance, it is impossible to have more than a single resumable handle that references it at runtime. We refer to this as the "single-resumer rule". Because both Task and WeakTask are move-only types that cannot be copy-constructed or copy-assigned from other handles, this guarantees at compile-time that there will never be two handles that are able to resume the same underlying coroutine. This compile-time guarantee was implemented after many insidious bugs emerged in gameplay code written using early versions of the Squid::Tasks library.

When a task's single-resumer handle is destroyed, the task is immediately killed. If a coroutine were able to remain suspended without the possibility of ever being resumed again, then any task waiting for it to terminate would deadlock. For this reason, Squid::Tasks enforces that all coroutines must have a valid resumable handle at all times, otherwise they are immediately killed.

(If you are unfamiliar with what it meant by "move-only type", we recommend you research "C++ move semantics" to familiarize yourself.)

Lifetime Management

The default lifetime of a Task's underlying coroutine is determined by the handles the refer to it:

  • The underlying coroutine will be killed immediately if it is no longer referenced by a resumable handle ( Task/ WeakTask).
  • The underlying coroutine will be killed immediately if it ever has zero strong references remaining to it ( Task/ TaskHandle).

This lifetime management model is essentially the same as a strong-pointer/weak-pointer model, with the added constraint that tasks are killed as soon as they can no longer logically be resumed.

Template Parameters
tRetReturn type of the underlying coroutine (can be void if the coroutine does not co_return a value)
RefTypeWhether this handle holds a strong or weak reference to the underlying coroutine
ResumableWhether this handle can be used to resume the underlying coroutine

Member Function Documentation

◆ CancelIf()

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
auto Task< tRet, RefType, Resumable >::CancelIf ( tTaskCancelFn  in_cancelFn) &&
inline

Returns wrapper task that kills this task when the given function returns true. Returns whether wrapped task was canceled. Task return value will be bool if wrapped task had void return type, otherwise std::optional<tRet>.

◆ CancelIfStopRequested()

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
auto Task< tRet, RefType, Resumable >::CancelIfStopRequested ( ) &&
inline

Returns wrapper task that kills this task when a stop request is issued on it. Returns whether wrapped task was canceled. Task return value will be bool if wrapped task had void return type, otherwise std::optional<tRet>.

◆ StopIf() [1/3]

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
auto Task< tRet, RefType, Resumable >::StopIf ( tTaskCancelFn  in_cancelFn) &&
inline

Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (without timeout).

Task returns whether wrapped task was canceled. Task return value will be bool if wrapped task had void return type, otherwise std::optional<tRet>. Returns wrapper task that requests a stop on this task when the given function returns true

◆ StopIf() [2/3]

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
auto Task< tRet, RefType, Resumable >::StopIf ( tTaskCancelFn  in_cancelFn,
tTaskTime  in_timeout 
) &&
inline

Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (with timeout in the global time-stream).

Task returns whether wrapped task was canceled. Task return value will be bool if wrapped task had void return type, otherwise std::optional<tRet>.

◆ StopIf() [3/3]

template<typename tRet = void, eTaskRef RefType = eTaskRef::Strong, eTaskResumable Resumable = eTaskResumable::Yes>
template<typename tTimeFn >
auto Task< tRet, RefType, Resumable >::StopIf ( tTaskCancelFn  in_cancelFn,
tTaskTime  in_timeout,
tTimeFn  in_timeFn 
) &&
inline

Returns wrapper task that requests a stop on this task when the given function returns true, then waits for the task to terminate (with timeout in a given time-stream).

Task returns whether wrapped task was canceled. Task return value will be bool if wrapped task had void return type, otherwise std::optional<tRet>.


The documentation for this class was generated from the following file: