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.