Table of Contents
Introduction to Coroutines in Lua
Basics of Coroutines
Creating a Coroutine:
A coroutine in Lua is created using the coroutine.create function, which takes a Lua function as an argument and returns a coroutine.
function foo()
print("Coroutine started")
coroutine.yield()
print("Coroutine resumed")
end
co = coroutine.create(foo)
Running a Coroutine:
To start or resume a coroutine, use coroutine.resume. This function runs the coroutine until it yields or terminates.
coroutine.resume(co) -- Output: Coroutine started coroutine.resume(co) -- Output: Coroutine resumed
Yielding a Coroutine:
Within a coroutine, you can pause its execution using coroutine.yield. This allows the coroutine to yield control back to the caller, who can then resume it later.
function bar()
for i = 1, 3 do
print("Iteration", i)
coroutine.yield()
end
end
co = coroutine.create(bar)
for i = 1, 3 do
coroutine.resume(co) -- Output: Iteration 1, Iteration 2, Iteration 3
end
Coroutine Status
You can check the status of a coroutine using coroutine.status. The possible statuses are:
- “running”: The coroutine is currently running.
- “suspended”: The coroutine is suspended and can be resumed.
- “normal”: The coroutine is active but not running (it has called yield).
- “dead”: The coroutine has finished its execution.
print(coroutine.status(co)) -- Output: suspended (after first yield) coroutine.resume(co) print(coroutine.status(co)) -- Output: dead (after finishing)
Coroutine Functions
Lua provides several functions to work with coroutines:
- coroutine.create(f): Creates a new coroutine with function f.
- coroutine.resume(co, …): Resumes the coroutine co, passing any arguments to it.
- coroutine.yield(…): Yields the coroutine, optionally passing values back to the caller.
- coroutine.status(co): Returns the status of the coroutine co.
- coroutine.running(): Returns the currently running coroutine.
Example 1: Coroutine with Arguments
You can pass arguments to coroutines and use them within the coroutine function.
function greet(name)
print("Hello, " .. name)
coroutine.yield()
print("Goodbye, " .. name)
end
co = coroutine.create(greet)
coroutine.resume(co, "Alice") -- Output: Hello, Alice
coroutine.resume(co) -- Output: Goodbye, Alice
Example 2: Coroutine Communication
Coroutines can yield and return values to the caller.
function add(a, b)
coroutine.yield(a + b)
end
co = coroutine.create(add)
success, result = coroutine.resume(co, 5, 7) -- Passes 5 and 7 to the coroutine
print(result) -- Output: 12
Example 3: Generating a Sequence with Coroutines
Coroutines can be used to generate sequences, such as the Fibonacci sequence.
function fibonacci()
local a, b = 0, 1
while true do
coroutine.yield(a)
a, b = b, a + b
end
end
co = coroutine.create(fibonacci)
for i = 1, 10 do
success, value = coroutine.resume(co)
print(value) -- Output: First 10 numbers of the Fibonacci sequence
end
Example 4: Coroutine as a Producer-Consumer
Coroutines can be used to implement producer-consumer patterns.
function producer()
local i = 0
while true do
i = i + 1
coroutine.yield(i)
end
end
function consumer()
while true do
local status, value = coroutine.resume(pro)
print("Consumed: " .. value)
end
end
pro = coroutine.create(producer)
consumer() -- This will consume and print the produced values indefinitely
Example 5: Simple State Machine with Coroutines
Coroutines can help in creating simple state machines.
function state_a()
print("In State A")
coroutine.yield("go to B")
print("Returning to State A")
end
function state_b()
print("In State B")
coroutine.yield("go to A")
end
state = {A = coroutine.create(state_a), B = coroutine.create(state_b)}
current_state = "A"
while true do
local status, next_state = coroutine.resume(state[current_state])
if not status then break end
current_state = (next_state == "go to A") and "A" or "B"
end
Example 6: Round-Robin Scheduling
Coroutines can be used for round-robin scheduling to manage multiple tasks.
function task1()
for i = 1, 3 do
print("Task 1, iteration " .. i)
coroutine.yield()
end
end
function task2()
for i = 1, 3 do
print("Task 2, iteration " .. i)
coroutine.yield()
end
end
tasks = {coroutine.create(task1), coroutine.create(task2)}
while true do
local all_done = true
for i = 1, #tasks do
if coroutine.status(tasks[i]) ~= "dead" then
coroutine.resume(tasks[i])
all_done = false
end
end
if all_done then break end
end