Nyx supports concurrent programming through threads and channels. A channel is a typed, buffered queue that lets threads communicate safely without shared mutable state. thread_spawn starts a new OS thread running a closure, while channel_send and channel_recv transfer values between threads.
// 20: Concurrency — spawn thread + channel communication fn main() -> int { let ch: Map = channel_new(5) fn producer() { var i: int = 0 while i < 5 { channel_send(ch, i * 10) i = i + 1 } } thread_spawn(producer) // Receive 5 values from the channel var total: int = 0 var n: int = 0 while n < 5 { let val: int = channel_recv(ch) print("received: " + int_to_string(val)) total = total + val n = n + 1 } print("total: " + int_to_string(total)) return 0 }
received: 0 received: 10 received: 20 received: 30 received: 40 total: 100
How it works
channel_new(capacity) creates a buffered channel that can hold up to capacity values before the sender blocks. The channel is typed as Map in the Nyx type system — this is an opaque handle to the underlying runtime channel struct. The capacity of 5 matches the number of values the producer will send, so no blocking occurs in this example.
The producer function is defined as a closure inside main, which means it captures ch from the enclosing scope. thread_spawn(producer) starts a new OS thread that runs producer concurrently with the rest of main. The channel acts as the synchronization point: channel_recv in the main thread will block until a value is available.
This producer-consumer pattern is fundamental to concurrent Nyx programs. For more complex coordination — multiple producers, fan-out, or timeouts — Nyx also provides select blocks (Go-style), Mutex, WaitGroup, and the M:N work-stealing scheduler. Channels remain the preferred way to pass data across thread boundaries because they eliminate the need for locks on shared state.