0Pricing
Lua Academy · レッスン

コルーチンの状態

coroutine.statusでコルーチンの状態(running、suspended、dead)を確認します。

「コルーチンの状態」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。

コルーチンの4つの状態

コルーチンには4つの状態があります。suspended(作成直後またはyield後で、実行を待機中)、running(現在実行中)、normal(別のコルーチンを実行させるために一時停止中)、dead(実行完了またはエラー発生)です。coroutine.status(co)で確認できます。

local co = coroutine.create(function()
  print(coroutine.status(coroutine.running()))  -- running
  coroutine.yield()
end)

print(coroutine.status(co))  -- suspended
coroutine.resume(co)          -- prints: running
print(coroutine.status(co))  -- suspended
coroutine.resume(co)
print(coroutine.status(co))  -- dead

「normal」状態

コルーチンが別のコルーチンをresumeすると、「normal」状態になります。実行中ではありません(実行中なのは別のコルーチンです)が、suspended状態でもありません。resumeしたコルーチンがyieldするのを待機しています。この状態が発生することはまれですが、複雑なコルーチングラフを理解するうえで重要です。

local inner, outer

inner = coroutine.create(function()
  print("outer status:", coroutine.status(outer))  -- normal
  coroutine.yield()
end)

outer = coroutine.create(function()
  coroutine.resume(inner)
end)

coroutine.resume(outer)
-- prints: outer status: normal

resume前の確認

特にループ内では、resumeする前に必ずコルーチンの状態を確認してください。dead状態のコルーチンをresumeするとエラーになります。running状態のコルーチンをresumeする場合もエラーになります(無限再帰が発生するためです)。

local function safeResume(co, ...)
  local status = coroutine.status(co)
  if status == "dead" then
    return false, "cannot resume dead coroutine"
  end
  if status == "running" then
    return false, "cannot resume running coroutine"
  end
  return coroutine.resume(co, ...)
end

エラー後の状態

コルーチン本体でキャッチされないエラーが発生すると、coroutine.resumeはfalseとエラーメッセージを返します。コルーチンは「dead」状態になります。再起動することはできないため、再試行する場合は新しいコルーチンを作成する必要があります。

local co = coroutine.create(function()
  error("something went wrong")
end)

local ok, err = coroutine.resume(co)
print(ok, err)                      -- false  ...: something went wrong
print(coroutine.status(co))         -- dead

-- Cannot resume dead coroutine:
local ok2, err2 = coroutine.resume(co)
print(ok2, err2)  -- false  cannot resume dead coroutine

coroutine.isyieldable

coroutine.isyieldable()は、実行中のコルーチンがyield可能な場合にtrueを返します。メインスレッドや、yieldをサポートしていないC関数内ではfalseを返します。コンテキストが不明な場合は、yieldする前に必ず確認してください。

local co = coroutine.create(function()
  print("isyieldable:", coroutine.isyieldable())  -- true
  coroutine.yield()
end)

coroutine.resume(co)

-- In main thread:
print("isyieldable:", coroutine.isyieldable())  -- false
-- coroutine.yield()  -- ERROR in main thread

コルーチンの集合の監視

コルーチンのプールを追跡し、resumeを一巡実行するたびにdead状態のコルーチンを削除します。これがタスクスケジューラーの基礎になります。

local function makeWorker(n, name)
  return coroutine.create(function()
    for i = 1, n do
      print(name, "step", i)
      coroutine.yield()
    end
  end)
end

local workers = {
  makeWorker(2, "fast"),
  makeWorker(4, "slow"),
}

while #workers > 0 do
  local alive = {}
  for _, co in ipairs(workers) do
    coroutine.resume(co)
    if coroutine.status(co) ~= "dead" then
      alive[#alive+1] = co
    end
  end
  workers = alive
end

コルーチンのデバッグ

状態の確認を利用して、コルーチンベースのコードに計測機能を追加し、デバッグしてください。状態の遷移を出力すると、処理の流れを理解しやすくなります。複雑なシステムでは、ラッパーテーブルを使ってコルーチンに名前を付けると、デバッグ出力が見やすくなります。

local function namedCo(name, fn)
  local co = coroutine.create(fn)
  return {
    co = co,
    name = name,
    resume = function(self, ...)
      print("[" .. self.name .. "] resume")
      local results = table.pack(coroutine.resume(self.co, ...))
      print("[" .. self.name .. "] status: " .. coroutine.status(self.co))
      return table.unpack(results, 1, results.n)
    end
  }
end

local worker = namedCo("worker1", function()
  coroutine.yield()
end)
worker:resume()
worker:resume()

dead状態のコルーチンの再起動

コルーチンがdead状態になると、resumeできません。「再起動」するには、同じ関数から新しいコルーチンを作成する必要があります。よく使われるパターンは、必要に応じて新しいコルーチンを作成するファクトリです。

local function makeCounter(start, step)
  return coroutine.wrap(function()
    local n = start or 0
    while true do
      coroutine.yield(n)
      n = n + (step or 1)
    end
  end)
end

local count = makeCounter(0, 2)
for i = 1, 5 do io.write(count() .. " ") end
print()  -- 0 2 4 6 8

-- "Restart" by creating a new one
count = makeCounter(100)
print(count())   -- 100

Coroutine.wrapのエラー動作

ラップされたコルーチンでエラーが発生すると、エラーはラッパー関数の呼び出し元まで伝播します。false+エラーを返すcoroutine.resumeとは異なり、wrapが返す関数はエラーを直接発生させます。エラーを捕捉する必要がある場合は、wrapの呼び出しをpcallで囲んでください。

local gen = coroutine.wrap(function()
  coroutine.yield(1)
  error("oops")
  coroutine.yield(2)  -- never reached
end)

print(gen())   -- 1 (ok)
local ok, err = pcall(gen)
print(ok, err) -- false  ...: oops
-- Subsequent call: dead coroutine
ok, err = pcall(gen)
print(ok, err) -- false  cannot resume dead coroutine

isyieldableとstatusの違い

コルーチンのコンテキストを調べる方法は2つあります。coroutine.status(co)は特定のコルーチンの状態を返し、coroutine.isyieldable()は現在の実行コンテキストがyield可能かどうかを示します。他のコルーチンを確認するにはstatusを、安全にyieldできるか確認するにはisyieldableを使用してください。

local function maybeYield()
  if coroutine.isyieldable() then
    coroutine.yield()
  else
    -- in main thread or non-yieldable context
    print("cannot yield here")
  end
end

maybeYield()  -- prints "cannot yield here" (main thread)

local co = coroutine.create(maybeYield)
coroutine.resume(co)   -- yields successfully

クイックチェック

コルーチンは本体の関数の実行を完了すると、どの状態になりますか?

復習:コルーチンの状態

まとめ:

  • 状態:suspended → running ↔ normal → dead
  • coroutine.status(co)は状態を表す文字列を返す
  • dead = 実行完了またはエラー発生、resume不可
  • coroutine.isyieldable()で現在のコンテキストがyield可能か確認
  • ループ内でresumeする前には必ず状態を確認
  • wrapのエラーは直接伝播し、resumeはfalse+errを返す

よくある質問

「コルーチンの状態」レッスンは無料ですか?

はい。「コルーチンの状態」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。

「コルーチンの状態」で何を学びますか?

coroutine.statusでコルーチンの状態(running、suspended、dead)を確認します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Lua Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「コルーチンの状態」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLua Academyレッスンでコードを書いて実行できますか?

はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. コルーチンの作成
  2. resumeとyield
  3. コルーチンの状態
  4. プロデューサー・コンシューマーパターン
← Lua Academyに戻る