Concurrency

Jda has built-in concurrency primitives: lightweight green threads, typed channels, atomics, and deadlock detection.

Green Threads (J-Threads)

spawn launches a function in a new green thread:

fn worker(id: i64) {
    print("worker ")
    print_i64(id)
    print("\n")
}

fn main() -> i64 {
    spawn worker(1)
    spawn worker(2)
    spawn worker(3)
    ret 0
}

J-Threads are cooperatively scheduled and much cheaper than OS threads. You can spawn thousands of them.

Channels

Channels provide typed communication between threads:

fn producer(ch: Channel<;i64>) {
    for i in range(100) {
        channel_send(ch, i)
    }
    channel_close(ch)
}

fn consumer(ch: Channel<;i64>) {
    loop channel_is_open(ch) {
        let val = channel_recv(ch)
        print_i64(val)
        print(" ")
    }
    print("\n")
}

fn main() -> i64 {
    let ch = channel_new<i64>()
    spawn producer(ch)
    spawn consumer(ch)
    ret 0
}

channel_send blocks if the channel is full. channel_recv blocks if the channel is empty. channel_close signals that no more values will be sent.

Fan-Out Pattern

Distribute work across multiple workers:

fn worker(id: i64, jobs: Channel<;i64>, results: Channel<;i64>) {
    loop channel_is_open(jobs) {
        let job = channel_recv(jobs)
        let result = process(job)
        channel_send(results, result)
    }
}

fn main() -> i64 {
    let jobs = channel_new<i64>()
    let results = channel_new<i64>()

    // spawn 4 workers
    for i in range(4) {
        spawn worker(i, jobs, results)
    }

    // send 100 jobs
    for i in range(100) {
        channel_send(jobs, i)
    }
    channel_close(jobs)

    ret 0
}

Atomics

For shared mutable state without channels:

let counter = atomic_new(0)

fn increment() {
    atomic_add(counter, 1)
}

fn main() -> i64 {
    for i in range(1000) {
        spawn increment()
    }
    let val = atomic_load(counter)
    print_i64(val)
    ret 0
}
FunctionDescription
atomic_new(val)Create atomic variable
atomic_load(a)Read current value
atomic_store(a, val)Write value
atomic_add(a, val)Add and return old value
atomic_cas(a, expected, new)Compare-and-swap

Deadlock Detection

Jda includes built-in deadlock detection. If all threads are blocked waiting on channels and no progress can be made, the runtime reports the deadlock and exits with an error message showing which threads are blocked and on which channels.

Race Detection

Use jda race to detect data races in concurrent programs:

jda race myapp.jda

This compiles with instrumentation for epoch-based happens-before analysis and reports any detected races.