Files
ziglings/exercises/092_async8.zig
2026-04-03 18:11:00 +02:00

63 lines
1.9 KiB
Zig

//
// Tasks often need to communicate! Io provides Queue for this —
// a bounded, thread-safe channel for passing data between tasks:
//
// var backing: [16]u32 = undefined;
// var queue: std.Io.Queue(u32) = .init(&backing);
//
// // Producer task:
// try queue.putOne(io, value); // blocks if queue is full
//
// // Consumer task:
// const val = try queue.getOne(io); // blocks if queue is empty
//
// When the producer is done, it calls queue.close(io) to signal
// that no more data is coming. After that, getOne() will return
// error.Closed once the queue is drained.
//
// This is the classic producer/consumer pattern — one task
// generates work, another processes it, and the queue handles
// all the synchronization automatically.
//
// Fix this program: the producer sends numbers 1..10, the
// consumer sums them up. The expected sum is 55.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
var backing: [4]u32 = undefined;
var queue: std.Io.Queue(u32) = .init(&backing);
var group: std.Io.Group = .init;
group.async(io, producer, .{ io, &queue });
group.async(io, consumer, .{ io, &queue });
try group.await(io);
}
fn producer(io: std.Io, queue: *std.Io.Queue(u32)) void {
// Send numbers 1 through 10 into the queue.
for (1..11) |i| {
// What Queue method sends a single element, blocking if full?
queue.???(io, @intCast(i)) catch return;
}
// Signal that we're done sending.
queue.close(io);
}
fn consumer(io: std.Io, queue: *std.Io.Queue(u32)) void {
var sum: u32 = 0;
while (true) {
const value = queue.getOne(io) catch |err| switch (err) {
error.Closed => break,
error.Canceled => return,
};
sum += value;
}
print("Sum of 1..10 = {}\n", .{sum});
}