- Simple Tasks
- Multiple Tasks
- Communicating Tasks
- Communicating Values
- Synchronising Tasks
- Buffered Communication
- Multiple Senders
- Conditional Tasks
As there is only one processor available, tasks have to queue in an orderly fashion to use it. The queue data structure is used to implement the active_tasks queue.
The identifiers of tasks in the queue are stored in order in the tasks field. There is space for all the tasks permitted by the system as defined in the task component by the max_tasks constant.
The number of tasks recorded in the queue at any one time is maintained by the count field. Only tasks which are ready to be executed will be held in the active_tasks queue, those that are waiting for a condition to become true, paused, sending, receiving, transputting or terminated will not be in the queue.
The head field is an index into the tasks array which controls access to the front of the queue where task identifiers are removed. Every time run_system is called, the virtual_machine executes the task at the front of the queue.
The tail field is an index into the tasks array which controls access to the back of the queue where task identifiers are added.
Both the head and the tail fields are advanced cyclically around the queue, however active entries can never be overwritten if the total number of tasks in the system is no larger than max_tasks.
Queues support the following functions.
void init_queue(queue* q);
This makes the queue empty by setting the count field to zero and making the head and tail fields to point at the same entry.
void enqueue(queue* q, byte id);
The enqueue function inserts an entry into the queue at the position indicated by the tail field. The tail field is then advanced cyclically to point at the next element and the count field is increased by one. Provided that the number of tasks never exceeds max_tasks, this function cannot be called when the queue is full.
byte dequeue(queue* q);
The dequeue function returns the task identifier from the tasks array element indicated by the head field. The head field is then advanced cyclically to point at the next element and the count field is decreased by one. This function should never be called if the queue is empty.
byte peek(queue* q);
The peek function returns the task identifier stored in the tasks array element indicated by the head field, but does not remove it from the queue. This function should never be called if the queue is empty.
byte queued(queue* q);
The queued function returns the number of queued tasks as indicated by the value of the count field.