Concurrency Overview
Planned — design subject to change
This feature is designed but not yet implemented. The syntax and behavior described here represent the target specification.
Model
Tape uses an actor model for concurrency:
- Threads are declared as named worker pools
- Communication is via typed messages (copy by default)
- No shared mutable state between threads
- No locks, no mutexes, no data races
Thread declaration
tape
thread ImageProcessor {
@pool(2, 8); // min 2, max 8 threads
fn resize(img: Image, width: i64, height: i64) -> Image {
// runs on a pool thread
return gfx.resize(img, width, height);
}
fn blur(img: Image, radius: f64) -> Image {
return gfx.blur(img, radius);
}
}Calling patterns
UI → Thread (non-blocking)
tape
// from UI thread — returns immediately, callback fires when done
ImageProcessor.resize(photo, 800, 600) -> on_resize_done;
fn on_resize_done(result: Image) {
display.set_image(result);
}Thread → Thread (blocking)
tape
// from another thread — blocks until result is ready
let processed = ImageProcessor.blur(img, 2.0);Data passing
All data is copied when sent to a thread. For large data, use readonly to enable zero-copy:
tape
fn process(readonly data: []u8) -> []u8 {
// data is frozen — cannot be mutated
// zero-copy transfer (no clone)
}No shared state
Each thread has its own isolated state. The only way to communicate is through function calls (messages). This eliminates data races by design.
Last modified: