PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ASURO Multitasking mit setjmp und alloca



rossir
06.01.2012, 21:59
Cooperatives Multitasking mit den Grundbausteinen:
- alloca
- setjmp/longjmp
Compiler Version: WinAVR-20100110
Asuro Lib: 2.80

Ich finde die Lösung spannend und wollte sie hier mal vorstellen:

Was macht der Code (Program: 2908 bytes (35.5% Full))?
0 blink_Task: Die StatusLED blinkt im Sekunden Takt.
1 avoid_Task: Wenn ASURO gegen ein Hindernis stößt fährt er zurück und dreht sich davon weg.
2 cruise_Task: ASURO fährt herum (gerade aus). cruise_Task und avoid_Task kommunizieren über die Variable is_collision.
3 background_Task: Mit der Restzeit werden rekursiv die Fibonacci Zahlen berechnet. Dies unerbittlich, solange der Stack reicht. Dann crasht das Programm (hier mal als Feature;)).

Die Kooperation findet durch die Funktion wait(millis) statt. Mit ihrem Aufruf wird die Kontrolle an einen anderen Task weiter gegeben. Der current Task wird dadurch erst frühestens nach millis Millisekunden wieder aktiviert d.h. "sein" wait(..) kehrt zurück. Mit anderen Worten: Aus der Sicht eines Task verrichten alle anderen Tasks ihre Arbeit innerhalb seines wait(millis).

Im Array tasks wird jeder Task mit seiner Startfunktion und seinem maximal zu erwartenden Stackbedarf eingetragen. (Achtung Feature: Für Task N-1 wird die Stackbedarfangabe ignoriert. Er verfügt damit über den kompletten verbleibenden Stackbereich des ASURO.) Die Priorität eines Tasks hängt von seiner Position in diesem Array ab. Task 0 hat die höchste Priorität.

In der main Funktion wird jeder Task initialisiert und sein Stackbedarf reserviert. Dann wird Task 0 gestartet und das kooperative Spiel beginnt.

#include "asuro.h"
#include <alloca.h>
#include <setjmp.h>

typedef struct {
void (*task )() ;
int stacksize;
unsigned long awakeAt;
jmp_buf env;
} Task_t;

const int slow=60, fast=80;
int currentTask;

extern void wait(int millis);

void blink_Task() {
int led=0;
while(1) {
led=1-led;
StatusLED(led);
wait(1000);
}
}

#define SWITCH_NOISE 5
int is_collision=0;

void avoid_Task() {
int count, old, sensor;
while(1) {
is_collision=0;
for(count=0; ; count++) {
sensor=PollSwitch();
if (old!=sensor) count=0;
old=sensor;
if (count>=SWITCH_NOISE && sensor!=0) break;
wait(10);
}
is_collision=1;
//what do when robot hit a wall?
SetMotorPower(-slow, -slow);
wait(2000);
if(sensor<16) SetMotorPower(-slow, 0); else SetMotorPower(0, -slow);
wait(1000);
}
}

void cruise_Task() {
while(1) {
if (is_collision==0) SetMotorPower(fast, fast);
wait(100);
}
}

long fib(int n) {
long r;
wait(0);
if (n<2) return 1;
r=fib(n-1)+fib(n-2);
wait(0);
return r;
};

void background_Task() {
int i;
for(i=0; ;i++) {
PrintInt(i); SerPrint(" "); PrintLong(fib(i)); SerPrint("\r\n");
}
}

Task_t tasks[] = {
{&blink_Task, 100},
{&avoid_Task, 100},
{&cruise_Task, 100},
{&background_Task},
};

#define TASKS (sizeof(tasks)/sizeof(Task_t))

void wait(int millis) {
tasks[currentTask].awakeAt=Gettime()+millis;
if (setjmp(tasks[currentTask].env)==0) {
for(currentTask=0; tasks[currentTask].awakeAt>Gettime(); ) {
currentTask=(currentTask+1)%TASKS;
}
longjmp(tasks[currentTask].env, 1);
}
}

int main(void) {
int i;
Init();
for(i=0; i<TASKS; i++) {
tasks[i].awakeAt=0;
if (setjmp(tasks[i].env)) {
(*tasks[currentTask].task)();
while(1) wait(30000);
}
if (i<TASKS-1) alloca(tasks[i].stacksize);
};
currentTask=0;
longjmp(tasks[currentTask].env, 1);
}
Andere Multitasking Varianten die hier (für den ASURO) vorgestellt wurden:
- Statemachine
- Subsumption
- FreeRTOS
Darüber hinaus habe ich gehört von:
- Femto OS
- NanoVM (JAVA)
JAVA hat das Multithreading schon auf Sprachebene integrierten. (Das bietet C erst ab C++11.) Jetzt unterstützt NanoVM leider ausgerechnet Threads nicht. Eigentlich Schade!