Concurrency
Green Threads with spawn
Braid provides concurrency through lightweight green threads. The spawnkeyword starts a new concurrent task that runs a block of code in its own execution context. These are managed by the BraidVM scheduler, not the OS.
fn main() {
spawn {
print("hello from a green thread!");
};
print("hello from main");
// both prints execute concurrently
}Multiple Spawns
You can spawn multiple concurrent tasks. The scheduler interleaves their execution cooperatively.
fn main() {
spawn {
let i = 0;
while i < 3 {
print("task a: " + i);
i = i + 1;
}
};
spawn {
let i = 0;
while i < 3 {
print("task b: " + i);
i = i + 1;
}
};
spawn {
let i = 0;
while i < 3 {
print("task c: " + i);
i = i + 1;
}
};
}Channels for Communication
Braid provides channels for communicating between concurrent tasks. Channels allow sending values from one task to another in a thread-safe manner.
fn main() {
let ch = channel();
spawn {
ch.send(42);
};
let val = ch.recv();
print("received: " + val);
}Channel Example: Producer-Consumer
A common pattern is one task producing values and another consuming them over a channel.
fn producer(ch: channel, count: int) {
let i = 0;
while i < count {
ch.send(i);
i = i + 1;
}
ch.close();
}
fn consumer(ch: channel) {
while true {
let val = ch.recv();
if val == nil {
break;
}
print("got: " + val);
}
}
fn main() {
let ch = channel();
spawn { producer(ch, 5); };
spawn { consumer(ch); };
}Buffered Channels
Channels can be created with a buffer size. A buffered channel allows sending without blocking until the buffer is full.
fn main() {
let ch = channel(10);
spawn {
let i = 0;
while i < 10 {
ch.send(i * i);
i = i + 1;
}
ch.close();
};
let sum = 0;
while true {
let val = ch.recv();
if val == nil {
break;
}
sum = sum + val;
}
print("sum: " + sum);
}Waiting for Tasks
Use a channel to synchronize task completion. The main task can wait until all spawned tasks signal they are done.
fn main() {
let done = channel();
let i = 0;
while i < 4 {
let id = i;
spawn {
print("task " + id + " starting");
// simulate work
let j = 0;
while j < 1000000 {
j = j + 1;
}
print("task " + id + " done");
done.send(true);
};
i = i + 1;
}
// wait for all 4 tasks
let count = 0;
while count < 4 {
done.recv();
count = count + 1;
}
print("all tasks complete");
}Spawn and Async Interop
The spawn block works alongside async functions. You can spawn a task that calls async functions internally.
async fn fetch_data(url: string) -> string {
// perform async network call
return "response data";
}
fn main() {
spawn {
let data = await fetch_data("https://example.com");
print("fetched: " + data);
};
print("main continues while fetch runs");
}