module Lapis::Docs::D_CONCURRENCY_AND_FIBERS::A_FIBERS_AND_COOPERATIVE_AWAIT

Overview

Fibers & Cooperative Signal Awaiting

Comprehensive guide to running Crystal fibers in Godot's single-threaded scene loop, cooperative yielding, and avoiding the top-level sleep deadlock trap.

Executive Summary & Key Topics

Topic Method / Anchor Description
The Three Golden Fiber Invariants .topic_00_fiber_rules Essential rules for writing asynchronous fiber code in LibGodot.
Yielding Execution in _process .topic_01_cooperative_yielding Pumping spawned fibers cooperatively from the engine main thread.
The Sleep Deadlock Hazard .topic_02_the_sleep_deadlock_hazard Why sleep hangs in fibers and how to await timers safely.

Related Guides & Source References

Defined in:

libgodot/docs/d_concurrency_and_fibers/a_fibers_and_cooperative_await.cr

Class Method Summary

Class Method Detail

def self.topic_00_fiber_rules : Nil #

The Three Golden Fiber Invariants: Essential rules for writing asynchronous fiber code in LibGodot.

Key Topics & Information

  • Rule 1: Godot owns the OS main loop; fibers must cooperatively yield via Fiber.yield
  • Rule 2: NEVER call top-level sleep in a fiber; Godot does not pump LibEvent
  • Rule 3: Use await(timer) or frame delta accumulators for time delays

def self.topic_01_cooperative_yielding : Nil #

Yielding Execution in _process: Pumping spawned fibers cooperatively from the engine main thread.

Because Godot controls the OS event loop, spawned fibers (spawn do ... end) will starve unless the main thread cooperatively yields:

node GameManager < Node do
  def _ready : Void
    # Spawn a background gameplay fiber
    spawn do
      Godot.print("Dialog sequence started!")
      await(get_tree.create_timer(2.0))
      Godot.print("2 seconds elapsed non-blockingly!")
    end
  end

  def _process(delta : Float64) : Void
    # Cooperatively yield time slice to pending fibers:
    Fiber.yield
  end
end

def self.topic_02_the_sleep_deadlock_hazard : Nil #

The Sleep Deadlock Hazard: Why sleep hangs in fibers and how to await timers safely.

The Hazard:

In standard Crystal console programs, sleep 2.seconds registers a timer with Crystal's LibEvent / IOCP event loop. In LibGodot, Godot drives the main loop — not LibEvent! Calling top-level sleep suspends the fiber permanently, hanging that fiber indefinitely.

The Safe Pattern:

Always use Godot's timer mechanism with await:

# SAFE: Suspends fiber until Godot's timer fires
await(get_tree.create_timer(1.5))