segue dalla parte 13
Coroutine
Come approccio alla programmazione concorrente, il linguaggio Lua non ha meccanismi interni per gestire nativamente i thread, ma si può appoggiare a ciò che offre il sistema operativo sottostante. Lua invece internamente offre il supporto alle coroutine: un programma Lua può avere diversi percorsi di esecuzione ‘parallela’ ognuno col proprio stack e variabili locali ma che condividono risorse e variabili globali con le altre coroutine.
La prima differenza sostanziale col modello classico dei thread è che in un determinato istante ‘gira’ una e una sola coroutine, mentre in un sistema multiprocessore ci possono essere più thread in esecuzione in contemporanea.
La seconda grande differenza è che nei thread c’è una entità esterna (di solito lo scheduler del il sistema operativo) che sovrintende all’ordine e assegna la ‘fetta’ di processore a disposizione di ciascun thread, mentre in Lua ciascuna coroutine decide quando è il momento di “sospendersi” per lasciare la CPU alle altre.
In questo caso, si parla infatti di cooperative multitasking. Le ragioni di questa scelta degli autori sono molteplici: anzitutto la semplicità di implementazione, poi ricordiamo il fatto che Lua è nato come linguaggio ’embedded’, perciò qualora ci fosse veramente bisogno dei thread si sfrutteranno le capacità del linguaggio ospitante.
Le funzionalità per gestire le coroutine in Lua sono raggruppate nel package ‘coroutine’. La prima funzione che serve è la create, che riceve come unico argomento una funzione e ritorna un valore di tipo thread:
>co=coroutine.create(function () print “ciao” end)
>print(co)
thread: 0x8408068
una coroutine può avere tre stati: suspended, running, dead. Una coroutine appena creata è in stato suspended:
>print(coroutine.status(co))
suspended
quindi per avviarla chiamiamo .resume :
>coroutine.resume(co)
ciao
ora la routine è terminata:
>print(coroutine.status(co))
dead
ogni coroutine può volontariamente ‘mettersi in pausa’ e passare alcuni valori tramite la funzione yield ; vediamo un semplice esempio:
NTHREADS=20
function ping()
print "ping"
coroutine.yield()
end
function pong()
print "pong"
coroutine.yield()
end
threads={}
for j=1,NTHREADS do
if j%2==0 then
threads[j]=coroutine.create(pong)
else
threads[j]=coroutine.create(ping)
end
end
running=true
while running do
for j=1,NTHREADS do
running=coroutine.resume(threads[j])
end
end
se volessimo invece sfruttare i thread del sistema operativo, si possono utilizzare librerie come Lanes oppure llthreads2 .