AIStatefulTask ‐ Asynchronous, Stateful Task Scheduler library.

Threads-like task objects evolving through user-defined states.

Classes | Public Member Functions | List of all members
AIEngine Class Reference

Detailed Description

Task queue and dispatcher.

This object dispatches tasks from mainloop().

Each of the member functions AIStatefulTask::run() end with a call to AIStatefulTask::reset() which in turn calls AIStatefulTask::multiplex(initial_run). When a default engine was passed to run then multiplex adds the task to the queue of that engine. When a thread pool queue was passed to run then the task is added to that queue of the thread pool. If the special AIQueueHandle immediate was passed to run then the task is being run immediately in the thread that called run and will keep running until it is either aborted or one of finish(), yield*() or wait*() is called!

Moreover, every time a task run with immediate as handler (and that didn't set a target handler) calls wait, then the task will continue running immediately when some thread calls signal(), and again keeps running!

If you don't want a call to run and/or signal to take too long, or it would not be thread-safe to not run the task from the main loop of a thread, then either pass a default engine, a thread pool queue, or (when the default handler is Handler::immediate) you've to make sure the task ‐ when (re)started ‐ quickly calls yield*() or wait*() (again), causing the task to be added to the highest priority queue of the thread pool.

Note that if during such engineless and queueless state yield() is called without passing a handler, then the task will be added to the highest priority queue of the thread pool.

Sinds normally ‐ for some instance of AIEngine ‐ it is the same thread that calls the AIEngine::mainloop member function in the main loop of that thread, there is a one-on-one relationship between a thread and an AIEngine object.

Once a task is added to an engine then every time the thread of that engine returns to its main loop, it processes one or more tasks in its queue until either — all tasks are finished, idle, moved to another handler or aborted — or, if a maximum duration was set, until more than max_duration milliseconds was spent in the mainloop (this applies to new tasks, not a task whose multiplex_impl is already called —only a frequent call to yield() is your friend there).

Note that each task object keeps track of three handlers:

The first, mTargetHandler, is the handler that was passed to the last call of member function AIStatefulTask::target (which is also called by the AIStatefulTask::yield*() member functions that take an engine or handler as parameter). It will be idle when target wasn't called yet, or when Handler::idle is explicitly passed as handler to one of these member functions.

The second, current_handler, is the handler that the task is added to ‐ for as long as the task needs to be run. It is Handler::idle when task didn't run at all yet or doesn't need to run anymore (e.g., when it is idle). As soon as this value is changed to a different value than the handler that the task is currently active in then that handler will not run that task anymore and remove it from its queue (if any); it is therefore the canonical handler that the task runs in. If a task goes idle, this value is set to Handler::idle; otherwise it is set to the last handler that that task did run in, which is the first non-idle handler from the top for the short list above.

The last, mDefaultHandler, is the handler that is passed to run and never changes.

#include <AIEngine.h>

Public Member Functions

 AIEngine (char const *name, float max_duration=0.0f)
void add (AIStatefulTask *stateful_task)
utils::FuzzyBool mainloop ()
void wake_up ()
 Wake up a sleeping engine.
void flush ()
char const * name () const
void setMaxDuration (float max_duration)
bool hasMaxDuration () const

Constructor & Destructor Documentation

◆ AIEngine()

AIEngine::AIEngine ( char const *  name,
float  max_duration = 0.0f 

Construct an AIEngine.

The argument name must be a string-literal (only the pointer to it is stored). If max_duration is less than or equal zero (the default) then no duration is set and the engine won't return from mainloop until all tasks in its queue either finished, are waiting (idle) or did yield to a different engine.

nameA human readable name for this engine. Mainly used for debug output.
max_durationThe maximum duration per loop (in milliseconds) during which new tasks are (re)started. See setMaxDuration.

Member Function Documentation

◆ add()

void AIEngine::add ( AIStatefulTask stateful_task)

Add stateful_task to this engine.

The task will remain assigned to the engine until it no longer active (tested after returning from multiplex_impl).

Normally you should not call this function directly. Instead, use AIStatefulTask::run.

stateful_taskThe task to add.

◆ flush()

void AIEngine::flush ( )

Flush all tasks from this engine.

All queued tasks are removed from the engine and marked as killed. This can be used when terminating a program, just prior to destructing all remaining objects, to avoid that tasks do call backs and use objects that are being destructed.

◆ hasMaxDuration()

bool AIEngine::hasMaxDuration ( ) const

Return true if a maximum duration was set.

Note, only engines with a set maximum duration can be used to sleep on by using AIStatefulTask::yield_frame or AIStatefulTask::yield_ms.

◆ mainloop()

utils::FuzzyBool AIEngine::mainloop ( )

The main loop of the engine.

Run all tasks that were added to the engine until they are all finished and/or idle, or until mMaxDuration milliseconds have passed if a maximum duration was set.

Returns true if there are still tasks in the engine that require CPU and mainloop() must be called again (the next frame). This is the case when one or more tasks called yield or when the call exceeded max_duration and there is still one or more task left that wasn't executed.

◆ name()

char const * AIEngine::name ( ) const

Return a human readable name of this engine.

This is simply the string that was passed upon construction.

◆ setMaxDuration()

void AIEngine::setMaxDuration ( float  max_duration)

Set mMaxDuration in milliseconds.

The maximum time the engine will spend in mainloop calling multiplex on unfinished and non-idle tasks. Note that if the last call to multiplex takes considerable time then it is possible that the time spend in mainloop will go arbitrarily far beyond mMaxDuration. It is the responsibility of the user to not run states (of task) that can take too long in engines that have an mMaxDuration set.

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