Il vantaggio principale dei protothread rispetto ai thread ordinari è che sono davvero leggeri: tutti i protothread sono eseguiti sullo stesso stack, e il cambio di contesto coincide con il riavvolgimento dello stack.
Ne consegue che definire un protothread ha la stessa complessità di definire una funzione C, a cui vanno aggiunti un “prologo” e un “epilogo”. Lo si fa con le annotazioni MR_PT_THREAD, seguita dalle macro MR_PTI_BEGIN e MR_PTI_END:
MR_PT_THREAD(function) {
MR_PTI_BEGIN();
// ... logic ...
MR_PTI_YIELD();
// ... logic ...
MR_PTI_END();
}
L'assenza dello stack è un vantaggio nei sistemi con stringenti vincoli di memoria, quelli cioè in cui uno stack per un thread potrebbe utilizzare gran parte della memoria disponibile. Invece, con i protothreads, ciò non avviene.
Un protothread richiede solo due byte di memoria per funzionare e tale spazio viene riservato allocando almeno una variabile del tipo mr_protothread:
mr_protothread functionThread;
Come è possibile notare, nella funzione viene chiamata almeno una volta la funzione MR_PTI_YIELD. Tale chiamata è necessaria perché, come abbiamo anticipato, si tratta di thread cooperativi e non preventivi: cioè vi è la necessità che il programmatore indichi il punto migliore in cui l'esecuzione può essere bloccata, e da cui riprendere.
Per mandare in esecuzione i thread è sufficiente chiamare (continuamente) la funzione con la seguente sintassi:
while(1) {
function(&functionThread);
}
Da notare come sia possibile eseguire N protothread con il medesimo codice, allocando N variabili di tipo mr_protothread e richiamando, in sequenza, ognuna di esse:
mr_protothread functionThread1;
mr_protothread functionThread2;
...
mr_protothread functionThreadN;
...
while(1) {
function(&functionThread1);
function(&functionThread2);
...
function(&functionThreadN);
}
Vai a COORDINARE I PROTOTHREAD