Action Planner

The trident::ActionPlanner template is responsible of planning actions based on requirements and provisions. In the trident::run a concrete implementation trident::RunActionPlanner is made by the specialization

struct RunActionPlanner : ActionPlanner<ProblemFunc, Predicate>

were ProblemFunc is a typedef for std::function<void(ProblemContext &)> and Predicate is a std::string.

The action planner consists of a set of requirements, provided by the various problem modules. Based on all requirements, the Action plan creates a plan for the asynchronous execution, by doing as many requirements in parallel as possible. The plan is made by iterating over all modules found in the provided problem context, and making the plan based on the trident::Capability. This class stores the needs, requirements, and what the capability provides, which is enough to build a topological tree of dependencies. Based on this tree, an asynchronous plan can be made, which is place in the trident::ActionPlan class.

The plan object can then execute the plan, and wait until a full execution is performed. The state of the plan for each module is stored in the trident::Action which represents a planned action to be performed by a module. It tracks the status of the action, and which other actions it depends upon, and after the action is performed, it is set to completed.

The asynchronous execution of the capabilities is performed using a thread-pool. The trident::AThredPool provides a tiny wrapper of a list of std::thread. These threads are created on initialization, and will run throughout the run, and will therefore not require any overhead when forked and joined. The tasks are provided by assigning the next task from the std::queue<Task>to an available worker (thread), until all tasks are done. This will then minimize the time where a worker does not have anything to do.

This procedure may be summarized by:

auto tp = std::make_shared<ThreadPool>(<num_threads>);
ActionPlan plan{tp};
ActionPlanner planner{state};

// Several capabilites and requirements defines in each module
planner.require(<some requirements as str>);
planner.make_plan(plan);

plan.execute();
plan.wait_for_actions();

A full architectural illustration is proved below:

actionplanner