Coroutinen
Den Coroutinen widmen wir hier ein extra Kapitel, da alles zusammen gehört.
Eine Coroutine ist eine besondere Art von Funktion. Man kann jede Funktion in eine Coroutine Umwandeln. Sehr wichtig um zu verstehen sind die Beispiele.
Wir sind es gewohnt, dass eine Funktion eins nach dem anderen abarbeitet bis das Ende erreicht ist.
Das macht eine Coroutine auch, nur mit einem gewaltigen Unterschied.
Man kann sie anhalten und nach Belieben irgendwann weiter laufen lassen. Alle Variablen, die bis dahin erarbeitet wurden, bleiben erhalten. Die Funktion macht an dieser Stelle weiter, als wenn nichts gewesen wäre. (Wenn sie wieder angestoßen wird)
Beispiele kommen zum Schluss, da man dies nur im Zusammenhang begreifen kann.
Die Funktionen für Coroutinen sind in dem Table
coroutine
gespeichert.
coroutine.create (f)
coroutine.resume (co, val1, ...)
coroutine.status (co)
coroutine.wrap (f)
coroutine.yield (val1, ...)
Coroutine - Beispiel 1
Coroutine - Beispiel 2
Coroutine - Beispiel 3
Coroutine - Beispiel 4
Diese Funktion erzeugt eine Coroutine.
Als Parameter ist folgendes zu übergeben:
- Die Funktion, die als Coroutine arbeiten soll.
meineRoutine = coroutine.create(DruckeEtwas) -- Die Coroutine
-- wird erzeugt, aber sie macht noch nichts. Sie muß erst angestoßen werden
Diese Funktion lässt eine Coroutine laufen. (Stößt sie an)
Als Parameter ist folgendes zu übergeben:
- Die Variable, die bei der Erschaffung der Coroutine zurückgegeben wurde.
Die Parameter werden nur beim ersten Aufruf der resume - Funktion übernommen. Bei jedem weiteren werden sie ignoriert.
Rückgabe ist zum einen der status der Funktion zum anderen die Parameter, die beim Anhalten der Funktion zurückgegeben werden
status, val1, ... = coroutine.resume( meineRoutine, 50)
-- Die Coroutine wird gestartet. Ein Parameter (hier 50) wird ihr übergeben.
Der Status ist true, wenn die Funktion ohne Error lief.
Val1, ... sind entweder die Werte, die beim Stoppen der Funktion übergeben werden, oder die Werte, die bei Beendigung der Funktion übergeben werden.
Diese Funktion gibt den derzeitigen Status der Coroutine als String zurück.
Als Parameter ist folgendes zu übergeben:
Die Variable, die bei der Erschaffung der Coroutine zurückgegeben wurde.
result = coroutine.status(meineRoutine)
result kann drei Zustände haben.
- "running" die Funktion läuft
- "suspended" die Funktion ist beurlaubt
- "dead" die Funktion ist beendet
Diese Funktion erzeugt ebenfalls eine Coroutine. Allerdings kann bei dieser nicht der Staus abgefragt werden.
Als Parameter ist folgendes zu übergeben:
Rückgabe ist eine Variable vom Typ "function"
meineAufrufFunktion = coroutine.wrap( DruckeEtwas)
-- Die Coroutine wird erzeugt
meineAufrufFunktion gibt entweder die Werte, die beim Stoppen der Funktion übergeben werden, oder die Werte, die bei Beendigung der Funktion übergeben werden zurück. Als Parameter gibt man die Parameter, die man übergeben möchte.
Value = meineAufrufFunktion(50)
Diese Funktion stoppt eine Coroutine. Daher muss sie innerhalb der Funktion liegen.
Als Parameter ist folgendes zu übergeben:
- Die Werte, die man resume oder der Aufruffunktion zurückgeben möchte.
coroutine.yield( 1000 )
Die Funktion (Coroutine) wird gestoppt und der Wert 1000 an die Aufruffunktion übergeben
function UeberwacheRoutine()
if value + beginnRoutine <= os.clock() *1000 then
coroutine.resume( meineRoutine)
-- hier wird die Coroutine zum zweiten Mal
-- gestartet. Es muss kein Parameter mehr da sein,
-- er würde so wie so ignoriert
return true
end
end
function DruckeEtwas(_wieviel)
print(_wieviel)
print ( "Status3 = "..coroutine.status(meineRoutine))
coroutine.yield( 1000 ) -- Stopp
_wieviel = _wieviel - 1
print(_wieviel)
end
beginnRoutine = os.clock() * 1000
-- Anfangszeit in 1000tel Sekunden
meineRoutine = coroutine.create( DruckeEtwas)
-- Die Coroutine wird erzeugt
print ( "Status1 = "..coroutine.status(meineRoutine))
status, value = coroutine.resume( meineRoutine, 50)
-- Die Coroutine wird zum ersten mal gestartet. ein Parameter
-- (hier 50 ) wird Ihr übergeben
print ( "Status2 = "..coroutine.status(meineRoutine))
while not UeberwacheRoutine() do end
-- solange die Funktion nicht true zurückgibt, wird sie immer
-- wieder ausgeführt
print ( "Status4 = "..coroutine.status(meineRoutine))
Ablauf Beispiel 1:
- Der Computer liest der Reihe nach die beiden Funktionen ein.
- Dann speichert er die Zeit in die Variable beginnRoutine
- Die Coroutine wird erzeugt und der thread in die Variable meineRoutine gespeichert
- Der derzeitige Status der Coroutine wird ausgedruckt. Da sie noch nicht läuft kommt suspended als Ergebnis
- Wir starten die Routine und übergeben Ihr den Parameter 50
- Die Routine druckt den Wert 50 aus.
- Die Routine druckt ihren Status aus: running. (sie läuft ja)
- Die Routine stoppt und übergibt an resume true und 1000
- true wird in die Variable status gespeichert und die 1000 in die Variable value
- Der derzeitige Status der Coroutine wird ausgedruckt. Da sie nicht mehr läuft kommt suspended als Ergebnis
- Dann geht es in eine Schleife, die so lange die Funktion UeberwacheRoutine ausführt bis diese einen Wert der ungleich
nil oder false ist zurück liefert - In der Funktion wird laufend geprüft ob die Beginnzeit um den Wert 1000 gestiegen ist. (1 Sekunde) Ist das der Fall,
so geht es in den Block. - Die Coroutine wird dann im Block zum zweiten Mal angestoßen und macht hinter yield weiter
- Dort wird von unserem Parameter 1 abgezogen und dann ausgedruckt.
- Die Funktion endet.
- Die Funktion UeberwacheRoutine endet damit, dass sie den Wert true zurückliefert.
- Damit ist die Bedingung für die while - Schleife false und diese endet auch.
- Der derzeitige Status der Coroutine wird ausgedruckt. Da sie beendet ist, kommt dead als Ergebnis.
function UeberwacheRoutine()
if value + beginnRoutine <= os.clock() *1000 then
beginnRoutine = os.clock() *1000
status, value = coroutine.resume( meineRoutine, 50)
end
end
function DruckeEtwas(_wieviel)
for i = 1, 10 do
print(_wieviel)
coroutine.yield( 1000 )
_wieviel = _wieviel - 1
end
return "ich habe fertig"
end
beginnRoutine = os.clock() *1000
meineRoutine = coroutine.create( DruckeEtwas)
status, value = coroutine.resume( meineRoutine, 50)
zeit = os.clock() *1000
while coroutine.status (meineRoutine) ~= "dead" do
UeberwacheRoutine()
end
print (value)
Wenn oben das verstanden ist, geht es hier etwas einfacher zu.
Bis auf die Schleife sieht es im ersten Augenblick ziemlich gleich aus.
- Die Coroutine startet, läuft in die for - Schleife, druckt aus und stoppt.
- Die 1000 werden wieder in value gespeichert. Die nächste Schleife läuft so lange, bis die Coroutine des Status "dead" hat,
also beendet ist. - Ist die Sekunde um, so wird die neue Zeit in die Variable beginnRoutine gespeichert.
- Die Routine wird wieder angestoßen.
- Zieht von _wieviel 1 ab und druckt es aus.
- Wieder Stopp. Rückgabe ist wieder 1000
- Jetzt überwacht die erste Funktion, ob die nächste Sekunde verstrichen ist.
- Das Ganze läuft weiter, bis die for - Schleife beendet ist
- Dann druckt es noch "ich habe fertig" aus
function UeberwacheRoutine()
if value + beginnRoutine <= os.clock() *1000 then
meineAufrufFunktion()
-- hier wird die Coroutine zum zweiten Mal
-- gestartet. Es muss kein Parameter mehr da sein,
-- er würde sowieso ignoriert
return true
end
end
function DruckeEtwas( _wieviel )
print(_wieviel)
coroutine.yield( 700 )
_wieviel = _wieviel - 1
print(_wieviel)
end
beginnRoutine = os.clock() *1000
-- Anfangszeit in 1000tel Sekunden
meineAufrufFunktion = coroutine.wrap( DruckeEtwas )
-- Die Coroutine wird erzeugt
value = meineAufrufFunktion( 50 )
-- Die Coroutine wird zum ersten Mal gestartet. ein Parameter
-- (hier 50 ) wird Ihr übergeben
while not UeberwacheRoutine() do end
-- solange die Funktion nicht true zurückgibt wird sie immer
-- wieder ausgeführt
Ähnlich wie im Beispiel 1 die Unterschiede:
1. Einmal die Art des Aufrufs und dann,
2. dass wir keinen Status abfragen können.
function UeberwacheRoutine()
if value + beginnRoutine <= os.clock() *1000 then
beginnRoutine = os.clock() *1000
value = meineAufrufFunktion()
end
end
function DruckeEtwas(_wieviel)
for i = 1, 10 do
print(_wieviel)
coroutine.yield( 50 )
_wieviel = _wieviel - 1
end
return -1
end
beginnRoutine = os.clock() *1000
meineAufrufFunktion = coroutine.wrap( DruckeEtwas) -- Die Coroutine wird erzeugt und die resum-Funktion gespeichert
value = meineAufrufFunktion(50) -- Die Coroutine wird zum ersten Mal gestartet. Ein Parameter (hier 50) wird Ihr übergeben
while value ~= -1 do
UeberwacheRoutine()
end
Der Unterschied zum Beispiel 2: Man muss sich etwas einfallen lassen um herauszufinden ob die Funktion beendet ist. (hier gebe ich -1 zurück)
Abfragen kann man es ja nicht
Die Vervielfältigung der auf diesen Seiten enthaltenen Informationen und Grafiken ist untersagt, ausgenommen davon ist sämtlicher auf diesen Seiten angezeigter Quellcode.
Siehe auch: Haftungsausschluss
Copyright © Robert Schmitz 2006
Siehe auch: Haftungsausschluss
Copyright © Robert Schmitz 2006