How to define and use a combinable function
version
1.1.1
scope
Example.
This code is provided as example code for a user to base their code on.
description
How to define and use a combinable function
boards
Unless otherwise specified, this example runs on the SliceKIT Core Board, but can easily be run on any XMOS device by using a different XN file.
Combinable functions represent tasks that can be combined to run on a single logical core.
If a tasks ends in an never-ending loop containing a select statement, it represents a task that continually reacts to events:
void task1(args) { .. initialization ... while (1) { select { case ... : break; case ... : break; ... } } }
These kind of tasks can be marked as combinable by adding a special attribute:
[[combinable]] void counter_task(char *taskId, int n) { int count = 0; timer tmr; unsigned time; tmr :> time; // This task perfoms a timed count a certain number of times, then exits while (1) { select { case tmr when timerafter(time) :> int now: printf("Counter tick at time %x on task %s\n", now, taskId); count++; if (count > n) return; time += 1000; break; } } }
A combinable function must obey the following restrictions:
- The function must have void return type.
- The last statement of the function must be a while(1)-select statement.
Several combinable functions can be run in parallel with a combined par. This will run them on the same logical core using co-operative multitasking:
int main() { [[combine]] par { counter_task("task1", 5); counter_task("task2", 2); } return 0; }
When tasks are combined the compiler creates code that first runs the initial sequence from each function (in an unspecified order) and then enters a main loop. This loop enables the cases from the main selects of each task and waits for one of the events to occur. When the event occurs, a function is called to implement the body of that case from the task in question before returning to the main loop.
You cannot use the [[combine]] attribute directly in a par with tile placements but can nest par statements:
int main(void) { par { on tile[0]: task1( ... ); on tile[1]: task2( ... ); on tile[1]: [[combine]] par { task3( ... ); task4( ... ); } } return 0; }
The above program will run task1 on a logical core on tile[0] and task2 on its own logical core on tile[1]. A further logical core on tile[1] will run both task3 and task4 by using co-operative multitasking.