Lua - Chaining Coroutines
Chaining coroutines is a nice way to organize operations or create complex control flows. We can make one coroutine yield its execution to another coroutine and then resume the earlier coroutine where it left off.
Most common way to chain coroutines is to use coroutine.yield() and coroutine.resume() methods.
Example - Chaining Using yield() and resume() methods
Using yield() and resume() methods is the most common way to chaining coroutines. A coroutine explicitly yields a value to indicate the next coroutine to be resumed. Now main thread is to pick up the signal and then resume the appropriate coroutine.
Define coroutines
-- function to represent coroutine1
function coroutine1()
print("Coroutine #1 started")
-- yield the current coroutine and signal to switch to next coroutine
coroutine.yield("switch", co2)
print("Coroutine #1 resumed")
end
-- function to represent coroutine2
function coroutine2()
print("Coroutine #2 started")
-- yield the current coroutine and signal to switch to next coroutine
coroutine.yield("switch", co3)
print("Coroutine #2 resumed")
end
-- function to represent coroutine3
function coroutine3()
print("Coroutine #3 started")
-- yield the current coroutine and signal as Done to mark end of chain.
coroutine.yield("done")
print("Coroutine #3 resumed")
end
Create coroutines
-- create co1 as first coroutine co1 = coroutine.create(coroutine1) -- create co2 as second coroutine co2 = coroutine.create(coroutine2) -- create co3 as third coroutine co3 = coroutine.create(coroutine3) -- set a current coroutine as co1 currentCo = co1
In main loop, chain coroutines as per yield values
-- infinite loop
while true do
-- start the current coroutine
local status, result = coroutine.resume(current_co)
-- if status is false, print the error
if not status then
print("Error:", result)
break
end
-- if value is switch
if result == "switch" then
-- get the second argument as next coroutine
currentCo = select(2, ...)
elseif result == "done" then -- end the chain
print("All coroutines finished")
break
end
end
Complete Example - Chaining coroutines
main.lua
-- function to represent coroutine1
function coroutine1()
print("Coroutine #1 started")
-- yield the current coroutine and signal to switch to next coroutine
coroutine.yield("switch", co2)
end
-- function to represent coroutine2
function coroutine2()
print("Coroutine #2 started")
-- yield the current coroutine and signal to switch to next coroutine
coroutine.yield("switch", co3)
end
-- function to represent coroutine3
function coroutine3()
print("Coroutine #3 started")
-- yield the current coroutine and signal as Done to mark end of chain.
coroutine.yield("done")
end
-- create co1 as first coroutine
co1 = coroutine.create(coroutine1)
-- create co2 as second coroutine
co2 = coroutine.create(coroutine2)
-- create co3 as third coroutine
co3 = coroutine.create(coroutine3)
-- set a current coroutine as co1
currentCo = co1
-- infinite loop
while true do
-- start the current coroutine
local status, result, co = coroutine.resume(currentCo)
-- if status is false, print the error
if not status then
print("Error:", result)
break
end
-- if value is switch
if result == "switch" then
-- get the second argument as next coroutine
currentCo = co
elseif result == "done" then -- end the chain
print("All coroutines finished")
break
end
end
Output
When we run the above code, we will get the following output−
Coroutine #1 started Coroutine #2 started Coroutine #3 started All coroutines finished
Explanation
Coroutine1 yiels a value "switch" and second value as coroutine instance co2 to be executed next.
In main loop, we're checking the value as "switch" and then setting the currentCo as the yielded coroutine co2.
Coroutine2 does the same and yields
Coroutine1 yiels a value "switch" and second value as coroutine instance co3.
Coroutine3 yiels a value "done" to mark the end of coroutine chain.