Using Lua Coroutines for Cooperative Multitasking
Learn how Lua coroutines enable lightweight cooperative multitasking, see a simple number‑generator example, understand status checks, and avoid common mistakes like resuming dead coroutines or stack overflow.
12 Feb 2026, 16:33 UTC

Why Use Coroutines
Coroutines are Lua’s built‑in mechanism for cooperative multitasking. They let a function pause its execution with coroutine.yield and later continue from the same point with coroutine.resume. Because the suspension happens in user space, a coroutine is far lighter than an OS thread and shares the same Lua state.
Basic Coroutine Example
The following script creates a coroutine that yields the numbers 1 through 5, then resumes it in a loop until it finishes.
local function number_generator()
for i = 1, 5 do
coroutine.yield(i) -- pause and return i to the caller
end
end
local co = coroutine.create(number_generator)
while coroutine.status(co) ~= 'dead' do
local ok, value = coroutine.resume(co)
if not ok then
-- error propagated from the coroutine
error(value)
end
print('yielded:', value)
end
Each iteration of the while loop asks the coroutine to run until it hits a yield. The yielded value becomes the second return of resume. When the function finishes, the coroutine enters the dead state and the loop ends.
Inspecting Coroutine State
Before each resume you can query coroutine.status(co). The possible strings are:
'suspended'– the coroutine has yielded and is waiting to be resumed.'running'– it is currently executing (only true inside the coroutine itself).'normal'– it has never been started or has finished yielding and is ready to run.'dead'– the coroutine has run to completion or has errored.
Checking the status helps avoid calling resume on a finished coroutine, which would raise an error.
Common Pitfalls and Limits
Calling resume on a dead coroutine
If you invoke coroutine.resume after the coroutine is 'dead', Lua throws an error like cannot resume dead coroutine. Wrapping the call in pcall (or xpcall) lets you handle the situation gracefully.
Deep recursion without yielding
A coroutine shares the same C stack as the rest of the Lua program. A recursive function that never yields can overflow the stack just like a regular Lua function. To stay safe, either rewrite the recursion as an iterative loop or insert occasional coroutine.yield calls to unwind the stack.
Yielding from C functions
Only Lua code can yield directly. If a C function called from Lua needs to yield, it must use the lua_yield C API; otherwise attempting to yield will raise an error.
Single‑threaded execution
Coroutines are cooperative: only one coroutine runs at a time. They do not provide parallelism on multi‑core CPUs. For true parallelism you must use OS threads or separate Lua states.
Practical Verification Steps
- Save the example script to a file, e.g.
test_coro.lua. - Run it with the Lua interpreter:
lua test_coro.lua. - Observe the printed lines; they should show the numbers 1 through 5 in order.
- Add a debug line before the loop:
print('status before:', coroutine.status(co))and after each resume to see the state change from'suspended'to'running'(inside the coroutine) and finally to'dead'. - To test error handling, replace the
whilecondition with an extra resume after the loop and wrap it inpcall; the second resume should returnfalseand an error message.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.