Lib/sequencer offers Multitasking
The lib/sequencer library implements one kind of cooperative multi-tasking of the event-driver kind. Unlike "pure" cooperative multi-tasking, a task cannot stop at any time (using an hypothetic yield feature) but only in known and stable states. That is conform to the Eiffel principles.
The principle is:
- the class LOOP_STACK manages the multi-tasking;
- the class JOB represents a task. The task core is the continue feature, in which the task controls the whole system;
- the class READY_DESCRIPTION allows to describe in which conditions a task can be executed.
We will successively see each of those concepts.
The multi-tasking manager
The class LOOP_STACK is in charge of managing the multi-tasking. It is used in two steps:
- initialisation: creation of the LOOP_STACK object, and adding of the tasks to execute
- execution: execution of the run feature
Of course, tasks can be added during the execution. The manager can also be stopped, thanks to the break feature.
A task has a life cycle represented by the features executed by the manager (indeed a LOOP_ITEM hence the export clauses of those fetaures).
- prepare allows to prepare the task; in this phase, the task sets the events upon which it wants to be activated. The READY_DESCRIPTION object is an object upon which one can set conditions (thanks to its when_* features).
- is_ready allows to test if the task has really been activated.The READY_DESCRIPTION object is an object upon which one can test conditions (thanks to its is_* features).
- continue contains the execution body of the task, and is executed if the task is really activated.
- done tells if the task has finished its execution. If so, it will be removed from the execution loop. Otherwise, the cycle begins again.
- restart allows to reinsert a task in the execution loop.
The restart feature is seldom useful. See Vision for some use cases.
The class READY_DESCRIPTION allows to set and test conditions. The possible conditions are:
- Time: this allows to create periodic tasks. See the classes PERIODIC_JOB and BACKGROUND_JOB;
- Data on an input stream: this allows to build tasks that wait for input data to be available (features when_data and is_data),
- Data on an output stream: this allows to build tasks that wait until they can write on an output stream (features when_free and is_free) ;
- Network: this allows to build tasks waiting network connections (features when_connection and is_connection).
The manager implements the following cycle:
- call to the feature READY_DESCRIPTION.reset;
- call to the feature prepare on each task;
- call to the feature READY_DESCRIPTION.wait to wait for at least one condition to happen;
- call to the feature is_ready on each task;
- for all the ready tasks, call to the feature continue;
- for those tasks, call to the feature done and if relevent, removal of the task;
- and back to the beginning.
Tasks are executed by priority order. Only the ready tasks with a lower priority are executed. The others, even if ready, will have to wait a future time when no other task with a lower priority is ready.
Libraries using the sequencer
- lib/net: servers usually allow to accept many simultaneous connexions. This is implemented thanks to the sequencer.
- lib/vision: the event manager loop is implemented with a sequencer.