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