Bibliothèque coroutine
La bibliothèque coroutine permet de créer des coroutines : des fonctions dont l'exécution peut être
suspendue (yield) puis reprise (resume) à volonté, un peu comme des threads coopératifs qui ne
s'exécutent jamais en parallèle. Elle est chargée automatiquement par OpenLibs() — aucun require
n'est nécessaire pour l'utiliser.
local co = coroutine.create(function(a)
print("premier resume, a =", a)
local b = coroutine.yield(a + 1)
print("second resume, b =", b)
return "terminé"
end)
print(coroutine.resume(co, 10)) --> true premier resume, a = 10 / true 11
print(coroutine.resume(co, 20)) --> second resume, b = 20 / true terminé
print(coroutine.status(co)) --> dead
Vue d'ensemble
| Fonction | Description |
|---|---|
coroutine.create(f) |
Crée une coroutine à partir de la fonction f, non démarrée |
coroutine.resume(co, ...) |
Démarre ou reprend l'exécution de co |
coroutine.yield(...) |
Suspend la coroutine appelante, en repassant les valeurs à resume |
coroutine.status(co) |
Statut de co : "running"/"suspended"/"normal"/"dead" |
coroutine.running() |
Coroutine en cours d'exécution, plus un booléen « est le thread principal » |
coroutine.isyieldable([co]) |
true si co (par défaut, la coroutine en cours) peut être suspendue |
coroutine.wrap(f) |
Comme create, mais retourne directement une fonction qui reprend la coroutine |
coroutine.close(co) |
Ferme une coroutine suspendue ou terminée, exécutant ses TBC en attente |
coroutine.create(f)
Crée une nouvelle coroutine dont le corps est la fonction f. Retourne un objet de type "thread",
initialement à l'état "suspended" (elle n'a pas encore commencé à s'exécuter — le premier
resume la démarre).
local co = coroutine.create(function() print("bonjour") end)
print(type(co)) --> thread
coroutine.resume(co [, val1, ···])
Démarre ou continue l'exécution de la coroutine co :
- Au premier appel,
codémarre son corps ;val1, ...sont passés comme arguments à la fonction. - Aux appels suivants (si
coest suspendue sur unyield),val1, ...deviennent les valeurs de retour de ceyield.
Si la coroutine s'exécute sans erreur, resume retourne true suivi des valeurs passées à yield
(si elle se suspend) ou des valeurs retournées par le corps (si elle se termine). En cas d'erreur
dans la coroutine, resume retourne false suivi du message d'erreur — l'erreur n'est pas
levée dans le contexte appelant, elle doit être testée explicitement :
local co = coroutine.create(function() error("oups") end)
local ok, err = coroutine.resume(co)
print(ok, err) --> false ...: oups
Reprendre une coroutine déjà "dead" ou "running"/"normal" retourne également false plus un
message d'erreur, plutôt que de lever une erreur script.
coroutine.yield(···)
Suspend l'exécution de la coroutine appelante. Les arguments deviennent les valeurs de retour
supplémentaires du resume correspondant. Les valeurs passées au resume suivant deviennent le
résultat de cet appel à yield :
local co = coroutine.create(function()
local x = coroutine.yield()
print("reçu :", x)
end)
coroutine.resume(co)
coroutine.resume(co, "salut") --> reçu : salut
Appeler coroutine.yield en dehors d'une coroutine (depuis le thread principal), ou depuis un
contexte non-suspendable, est une erreur.
coroutine.wrap(f)
Comme coroutine.create, crée une nouvelle coroutine avec corps f, mais retourne directement une
fonction qui la reprend à chaque appel (au lieu de retourner la coroutine elle-même). Contrairement
à coroutine.resume, une erreur dans la coroutine n'est pas ramenée sous forme de valeur : elle
est propagée dans le contexte appelant, comme une erreur normale (à intercepter avec pcall si
besoin).
local gen = coroutine.wrap(function()
for i = 1, 3 do coroutine.yield(i) end
end)
print(gen(), gen(), gen()) --> 1 2 3
coroutine.status(co)
Retourne le statut de co sous forme de chaîne :
| Statut | Signification |
|---|---|
"running" |
co est celle qui appelle status (elle s'exécute actuellement) |
"suspended" |
co est suspendue sur un yield, ou n'a pas encore démarré |
"normal" |
co est active mais pas en cours d'exécution (elle a repris une autre coroutine) |
"dead" |
co a terminé son corps, normalement ou par une erreur |
coroutine.running()
Retourne deux valeurs : la coroutine en cours d'exécution, et un booléen valant true si cette
coroutine est le thread principal (celui qui existe en dehors de tout coroutine.create).
coroutine.isyieldable([co])
Retourne true si co (par défaut, la coroutine en cours) peut actuellement être suspendue par
yield. Une coroutine n'est pas suspendable si c'est le thread principal.
coroutine.close(co)
Ferme la coroutine co : exécute ses variables to-be-closed (TBC) en attente et la place à l'état
"dead". co doit être "dead" ou "suspended" — la fermer alors qu'elle est "running" ou
"normal" est une erreur script.
Retourne true en cas de succès, ou false plus le message d'erreur si la fermeture d'une valeur
TBC (ou l'erreur d'origine qui avait arrêté la coroutine) a échoué :
local co = coroutine.create(function()
local guard <close> = setmetatable({}, { __close = function() print("fermé") end })
coroutine.yield()
end)
coroutine.resume(co)
print(coroutine.close(co)) --> fermé / true