Concurrency

Toka provides lightweight concurrency through tasks and message passing, enabling efficient parallel execution.

Tasks

Spawn concurrent tasks with the task module:

import std/io::println
import std/thread::thread_spawn

fn worker(id: i32) -> i32 {
    println("Worker {} started", id)
    // Do work...
    println("Worker {} done", id)
    return 0
}

fn main() -> i32 {
    auto t1# = thread_spawn<i32>({ => return cede worker(1) })
    auto t2# = thread_spawn<i32>({ => return cede worker(2) })
    
    t1#.join()
    t2#.join()
    return 0
}

MPSC Channels

Communicate between tasks using MPSC (Multi-Producer, Single-Consumer) channels:

import std/channel::channel
import std/thread::thread_spawn
import std/io::println

fn main() -> i32 {
    auto pair# = channel<i32>()
    
    auto tx# = cede pair.tx
    auto rx# = cede pair.rx
    
    thread_spawn<i32>({ [cede tx] => 
        tx#.send(cede 42)
        return cede 0
    })
    
    thread_spawn<i32>({ [cede rx] =>
        auto res_opt = rx#.recv()
        println("Got a message!")
        return cede 0
    })
    
    return 0
}

Atomic Operations

Use atomic types for lock-free concurrent access:

import std/atomic::*

fn main() -> i32 {
    auto counter = AtomicI32::new(0)
    counter.fetch_add(1, Ordering::SeqCst)
    return 0
}

Mutex / Sync

For shared mutable state:

import std/sync::Mutex

fn main() -> i32 {
    auto lock# = Mutex<i32>::new(0:i32)
    
    auto g = lock#.lock().unwrap()
    // Access shared data safely
    // g released automatically when it goes out of scope
    return 0
}

Safety Guarantees

Toka's concurrency model prevents:

  • Data races: Two tasks cannot simultaneously write to the same memory
  • Deadlocks: The compiler analyzes lock ordering
  • Send/Sync violations: Types that are not thread-safe cannot be shared across tasks