CodeToLive

Coroutines in Lua

Coroutines are a powerful feature in Lua that allow for cooperative multitasking. Unlike threads in other languages, coroutines are not preemptive - they yield control voluntarily.

Basic Coroutine Operations

Creating and running a coroutine:

-- Create a coroutine
local co = coroutine.create(function()
    print("Hello from coroutine")
end)

-- Run the coroutine
coroutine.resume(co)

Yielding and Resuming

Coroutines can yield control and later be resumed:

local co = coroutine.create(function()
    print("First")
    coroutine.yield()
    print("Second")
end)

coroutine.resume(co)  -- Prints "First"
coroutine.resume(co)  -- Prints "Second"

Passing Values

You can pass values between yield and resume:

local co = coroutine.create(function(a, b)
    print("Received:", a, b)
    local sum = a + b
    sum = coroutine.yield(sum)
    print("Received after yield:", sum)
    return sum * 2
end)

-- First resume (starts the coroutine)
local _, initialSum = coroutine.resume(co, 2, 3)
print("Yielded sum:", initialSum)  -- 5

-- Second resume (after yield)
local _, finalResult = coroutine.resume(co, initialSum * 10)
print("Final result:", finalResult)  -- 100

Coroutine Status

Check a coroutine's status with coroutine.status:

print(coroutine.status(co))  -- "suspended", "running", or "dead"

Producer-Consumer Pattern

A common use of coroutines is implementing producer-consumer patterns:

function producer()
    local i = 0
    return function()
        i = i + 1
        coroutine.yield(i)
    end
end

local prod = producer()
local co = coroutine.create(function()
    while true do
        prod()
    end
end)

-- Consumer
for i = 1, 5 do
    coroutine.resume(co)
    print(coroutine.status(co), select(2, coroutine.resume(co)))
end

Coroutines vs Threads

Key differences between coroutines and threads:

  • Coroutines are cooperative (must yield explicitly)
  • Only one coroutine runs at a time
  • No need for locks or synchronization
  • Much lighter weight than OS threads

Asynchronous Programming

Coroutines are often used with event loops for async programming:

-- Pseudocode for async I/O with coroutines
function async_read(file)
    local co = coroutine.running()
    register_callback(function(data)
        coroutine.resume(co, data)
    end)
    return coroutine.yield()
end

-- Usage in a coroutine
coroutine.create(function()
    local data = async_read("file.txt")
    print("Received data:", data)
end)

Next Steps

Now that you understand coroutines, learn about error handling in Lua.