Lua Logo
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





nach obencoroutine.create

Diese Funktion erzeugt eine Coroutine.

Als Parameter ist folgendes zu übergeben:
Rückgabe ist eine Variable vom Typ "thread" (ein eigener Typ um diese Coroutines durchzuführen)

    meineRoutine = coroutine.create(DruckeEtwas) -- Die Coroutine
                        -- wird erzeugt, aber sie macht noch nichts. Sie muß erst angestoßen werden
    

nach obencoroutine.resume

Diese Funktion lässt eine Coroutine laufen. (Stößt sie an)

Als Parameter ist folgendes zu übergeben:

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.



nach obencoroutine.status

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.

"dead" tritt bei normaler Beendigung oder auch bei Beendigung durch einen Fehler auf.



nach obencoroutine.wrap

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)
    





nach obencoroutine.yield

Diese Funktion stoppt eine Coroutine. Daher muss sie innerhalb der Funktion liegen.

Als Parameter ist folgendes zu übergeben:
Rückgabe keine.
    
    coroutine.yield( 1000 )
    

Die Funktion (Coroutine) wird gestoppt und der Wert 1000 an die Aufruffunktion übergeben



nach obenCoroutine - Beispiel 1



    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:






nach obenCoroutine - Beispiel 2

    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 = 110 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.


nach obenCoroutine - Beispiel 3




    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.






nach obenCoroutine - Beispiel 4


    function UeberwacheRoutine()
        if value + beginnRoutine <= os.clock() *1000 then
            beginnRoutine = os.clock() *1000
            value = meineAufrufFunktion()
        end
    end
    
    function DruckeEtwas(_wieviel)
        for i = 110 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

nach obenEnde Coroutinen
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