Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Lua Dictionary
  3. coroutine.create() / resume() / yield()

coroutine.create() / resume() / yield()

Lua natively supports coroutines through the coroutine library, enabling cooperative multitasking. Unlike threads, no preemption occurs, so the design must explicitly yield control.

Syntax

-- -----------------------------------------------
-- Basic coroutine syntax
-- -----------------------------------------------

-- coroutine.create() creates a coroutine (not yet running)
local co = coroutine.create(function(a, b)
    print("start:", a, b)             -- executed on first resume
    local c = coroutine.yield(a + b)  -- returns value and suspends
    print("resumed:", c)              -- resumes on next resume
end)

-- coroutine.resume() starts or resumes the coroutine
local ok, val = coroutine.resume(co, 10, 20)
print(ok, val)                        -- true  30

local ok2, val2 = coroutine.resume(co, 99)
print(ok2, val2)                      -- true  nil (function ended)

-- -----------------------------------------------
-- coroutine.status() checks the coroutine state
-- -----------------------------------------------
-- "dead"     : finished
-- "suspended": yielded or not yet started
-- "running"  : currently executing
-- "normal"   : resuming another coroutine

local co2 = coroutine.create(function()
    coroutine.yield()
end)
print(coroutine.status(co2))      -- suspended
coroutine.resume(co2)
print(coroutine.status(co2))      -- suspended (paused at yield)
coroutine.resume(co2)
print(coroutine.status(co2))      -- dead

-- -----------------------------------------------
-- coroutine.wrap() creates a coroutine callable as a function
-- -----------------------------------------------
local gen = coroutine.wrap(function()
    for i = 1, 3 do
        coroutine.yield(i)        -- returns the next value on each call
    end
end)

print(gen())   -- 1
print(gen())   -- 2
print(gen())   -- 3

Syntax Reference

Function / ConceptDescription
coroutine.create(fn)Creates and returns a coroutine with fn as its body. The coroutine starts in the suspended state.
coroutine.resume(co, ...)Starts or resumes coroutine co. Extra arguments become the body function's arguments on the first call, or the return value of the preceding yield on subsequent calls. Returns true/false plus values yielded or returned at termination.
coroutine.yield(...)Suspends the coroutine and returns values to the caller (the side that called resume). The passed values become the return values of resume.
coroutine.status(co)Returns the coroutine state as a string: "suspended", "running", "dead", or "normal".
coroutine.wrap(fn)Returns a function that wraps the coroutine. Each call resumes it and returns the yielded value. Raises an exception on error.
coroutine.isyieldable()Returns whether yield is possible in the current execution context. Returns false outside a coroutine.
First return value of resumeReturns true on normal completion or yield; returns false and an error message on runtime error.
Producer/consumer patternOne side generates data and yields it; the other side receives it via resume. Well suited for implementing generators.

Sample Code

kof_coroutine.lua
-- kof_coroutine.lua — coroutine basics sample
-- Uses KOF (The King of Fighters) characters to demonstrate
-- coroutine.create / resume / yield / wrap

-- -----------------------------------------------
-- Producer/consumer pattern
-- -----------------------------------------------

-- Creates a producer that yields fighters one by one
local fighters = {
    { name = "Kusanagi Kyo",   team = "Japan Team",     power = 950 },
    { name = "Yagami Iori",    team = "Yagami Team",    power = 960 },
    { name = "Terry Bogard",   team = "Fatal Fury Team", power = 900 },
    { name = "Mai Shiranui",   team = "Fatal Fury Team", power = 870 },
    { name = "Leona Heidern",  team = "Heidern Team",   power = 920 },
}

-- Coroutine body: yields one fighter per call
local producer = coroutine.create(function()
    for _, fighter in ipairs(fighters) do
        coroutine.yield(fighter)  -- passes one entry to the caller and suspends
    end
end)

-- Consumer: repeatedly resumes to receive data
print("=== KOF Entry Registration ===")
while true do
    local ok, fighter = coroutine.resume(producer)
    if not ok or fighter == nil then
        break                     -- exit when coroutine ends or no data remains
    end
    print(string.format("  [%s] %s (Power: %d)", fighter.team, fighter.name, fighter.power))
end
print("")

-- -----------------------------------------------
-- Generator using coroutine.wrap()
-- -----------------------------------------------

-- Creates a generator that returns fighters with power >= threshold
local function make_fighter_gen(list, threshold)
    return coroutine.wrap(function()
        for _, f in ipairs(list) do
            if f.power >= threshold then
                coroutine.yield(f)  -- yield only when condition is met
            end
        end
    end)
end

local strong_gen = make_fighter_gen(fighters, 920)

print("=== Fighters with Power >= 920 ===")
for f in strong_gen do           -- a wrap-returned function works as a for iterator
    print(string.format("  %s: %d", f.name, f.power))
end
print("")

-- -----------------------------------------------
-- Two-way communication using resume arguments
-- -----------------------------------------------

-- Referee coroutine: advances the match while receiving challenger names
local referee = coroutine.create(function(first_challenger)
    local challenger = first_challenger
    local round = 1
    while true do
        local result = string.format("Round %d: %s wins!", round, challenger)
        local next_challenger = coroutine.yield(result)  -- returns result and waits for next challenger
        if next_challenger == nil then
            break                 -- terminate when nil is received
        end
        challenger = next_challenger
        round = round + 1
    end
end)

print("=== Tournament ===")
-- Start the coroutine with the first challenger
local ok1, res1 = coroutine.resume(referee, "Kusanagi Kyo")
print("  " .. res1)

-- Resume with the next challenger (delivered as the return value of yield)
local ok2, res2 = coroutine.resume(referee, "Yagami Iori")
print("  " .. res2)

local ok3, res3 = coroutine.resume(referee, "Terry Bogard")
print("  " .. res3)

-- Pass nil to terminate the coroutine
coroutine.resume(referee, nil)
print("  Tournament ended. Status: " .. coroutine.status(referee))
print("")

-- -----------------------------------------------
-- Error handling (checking resume return values)
-- -----------------------------------------------

-- A coroutine that intentionally raises an error
local buggy = coroutine.create(function()
    coroutine.yield("ready")
    error("Mai Shiranui's Ryuenbu KO!")  -- raises an error
end)

local s1, v1 = coroutine.resume(buggy)
print("=== Error Handling ===")
print("  1st ok=" .. tostring(s1) .. "  val=" .. tostring(v1))

local s2, v2 = coroutine.resume(buggy)
print("  2nd ok=" .. tostring(s2) .. "  err=" .. tostring(v2))
print("  Status: " .. coroutine.status(buggy))  -- dead
print("")

-- -----------------------------------------------
-- Verifying status transitions
-- -----------------------------------------------

print("=== Status Transitions ===")
local co = coroutine.create(function()
    coroutine.yield()
    coroutine.yield()
end)

print("  After create:    " .. coroutine.status(co))   -- suspended
coroutine.resume(co)
print("  After 1st yield: " .. coroutine.status(co))  -- suspended
coroutine.resume(co)
print("  After 2nd yield: " .. coroutine.status(co))  -- suspended
coroutine.resume(co)
print("  After finish:    " .. coroutine.status(co))  -- dead
lua kof_coroutine.lua
=== KOF Entry Registration ===
  [Japan Team] Kusanagi Kyo (Power: 950)
  [Yagami Team] Yagami Iori (Power: 960)
  [Fatal Fury Team] Terry Bogard (Power: 900)
  [Fatal Fury Team] Mai Shiranui (Power: 870)
  [Heidern Team] Leona Heidern (Power: 920)

=== Fighters with Power >= 920 ===
  Kusanagi Kyo: 950
  Yagami Iori: 960
  Leona Heidern: 920

=== Tournament ===
  Round 1: Kusanagi Kyo wins!
  Round 2: Yagami Iori wins!
  Round 3: Terry Bogard wins!
  Tournament ended. Status: dead

=== Error Handling ===
  1st ok=true  val=ready
  2nd ok=false  err=input:2: Mai Shiranui's Ryuenbu KO!
  Status: dead

=== Status Transitions ===
  After create:    suspended
  After 1st yield: suspended
  After 2nd yield: suspended
  After finish:    dead

Common Mistakes

Common Mistake 1: Trying to resume a dead coroutine

Calling resume on a coroutine that has already finished (dead) returns false and an error message. Continuing to use the coroutine without checking the return value leads to bugs.

ng_example.lua
local co = coroutine.create(function()
    coroutine.yield(1)
end)

coroutine.resume(co)  -- 1st: pauses at yield
coroutine.resume(co)  -- 2nd: function ends (dead)
local ok, val = coroutine.resume(co)  -- 3rd: resume on dead coroutine
print(ok, val)
false	cannot resume dead coroutine

Check the status before calling resume, or check the first return value (ok) before proceeding.

ok_example.lua
local co = coroutine.create(function()
    coroutine.yield(1)
end)

while coroutine.status(co) ~= "dead" do
    local ok, val = coroutine.resume(co)
    if not ok then break end
    if val ~= nil then print(val) end
end
print("status:", coroutine.status(co))
1
status:	dead

Common Mistake 2: Missing that errors in coroutine.wrap raise exceptions

When an error occurs inside a function created with coroutine.wrap, unlike resume, a Lua exception is thrown. Without protecting with pcall, the program terminates.

ng_example2.lua
local gen = coroutine.wrap(function()
    coroutine.yield("ok")
    error("something went wrong")
end)

gen()  -- 1st: returns "ok"
gen()  -- 2nd: exception is thrown (not caught, so program crashes)
lua: ng_example2.lua:3: something went wrong
stack traceback:
	[C]: in function 'error'
	ng_example2.lua:3: in function 
	ng_example2.lua:7: in main chunk
	[C]: in ?

Wrap the call in pcall, or use coroutine.create and coroutine.resume when error handling is required.

ok_example2.lua
local co = coroutine.create(function()
    coroutine.yield("ok")
    error("something went wrong")
end)

local ok1, v1 = coroutine.resume(co)
print(ok1, v1)  -- true  ok

local ok2, v2 = coroutine.resume(co)
print(ok2, v2)  -- false  error message
true	ok
false	input:3: something went wrong

Overview

Lua coroutines are a mechanism for cooperative multitasking. Unlike OS threads, switching between coroutines occurs only through explicit calls to coroutine.resume() and coroutine.yield(). This enables safe state sharing without locks.

coroutine.create() creates the coroutine object without executing it. Extra arguments passed to coroutine.resume() arrive as the body function's arguments on the first call, and as the return value of the preceding yield on subsequent calls. Conversely, values passed to yield arrive at the caller as the second and subsequent return values of resume. This bidirectional value passing makes it straightforward to implement the producer/consumer pattern.

coroutine.wrap() wraps a coroutine as a function and is convenient for building generators usable as iterators in for loops. Note that unlike resume, errors raise exceptions. resume returns false as the first return value plus an error message, enabling safer error handling. For related topics, also see the Generic for and Iterators and Function Basics pages.

If you find any errors or copyright issues, please .