mirror of
https://codeberg.org/ziglings/exercises.git
synced 2026-06-08 07:50:00 +00:00
added async-io quiz
This commit is contained in:
46
build.zig
46
build.zig
@@ -1109,20 +1109,29 @@ const exercises = [_]Exercise{
|
|||||||
.main_file = "083_anonymous_lists.zig",
|
.main_file = "083_anonymous_lists.zig",
|
||||||
.output = "I say hello!",
|
.output = "I say hello!",
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
.main_file = "084_interfaces.zig",
|
||||||
|
.output =
|
||||||
|
\\Daily Insect Report:
|
||||||
|
\\Ant is alive.
|
||||||
|
\\Bee visited 17 flowers.
|
||||||
|
\\Grasshopper hopped 32 meters.
|
||||||
|
, // pay attention to the comma
|
||||||
|
},
|
||||||
|
|
||||||
// Skipped because of https://github.com/ratfactor/ziglings/issues/163
|
// Skipped because of https://github.com/ratfactor/ziglings/issues/163
|
||||||
// direct link: https://github.com/ziglang/zig/issues/6025
|
// direct link: https://github.com/ziglang/zig/issues/6025
|
||||||
.{
|
.{
|
||||||
.main_file = "084_async.zig",
|
.main_file = "085_async.zig",
|
||||||
.output = "Current time: <timestamp>s since epoch",
|
.output = "Current time: <timestamp>s since epoch",
|
||||||
.timestamp = true,
|
.timestamp = true,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "085_async2.zig",
|
.main_file = "086_async2.zig",
|
||||||
.output = "Computing... the answer is: 42",
|
.output = "Computing... the answer is: 42",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "086_async3.zig",
|
.main_file = "087_async3.zig",
|
||||||
.output =
|
.output =
|
||||||
\\1 + 2 = 3
|
\\1 + 2 = 3
|
||||||
\\6 * 7 = 42
|
\\6 * 7 = 42
|
||||||
@@ -1130,7 +1139,7 @@ const exercises = [_]Exercise{
|
|||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "087_async4.zig",
|
.main_file = "088_async4.zig",
|
||||||
.output =
|
.output =
|
||||||
\\Task 1 done.
|
\\Task 1 done.
|
||||||
\\Task 2 done.
|
\\Task 2 done.
|
||||||
@@ -1139,7 +1148,7 @@ const exercises = [_]Exercise{
|
|||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "088_async5.zig",
|
.main_file = "089_async5.zig",
|
||||||
.output =
|
.output =
|
||||||
\\Starting long computation...
|
\\Starting long computation...
|
||||||
\\Canceling slow task...
|
\\Canceling slow task...
|
||||||
@@ -1148,19 +1157,19 @@ const exercises = [_]Exercise{
|
|||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "089_async6.zig",
|
.main_file = "090_async6.zig",
|
||||||
.output = "Hare: I'm fast!",
|
.output = "Hare: I'm fast!",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "090_async7.zig",
|
.main_file = "091_async7.zig",
|
||||||
.output = "Counter: 400",
|
.output = "Counter: 400",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "091_async8.zig",
|
.main_file = "092_async8.zig",
|
||||||
.output = "Sum of 1..10 = 55",
|
.output = "Sum of 1..10 = 55",
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "092_async9.zig",
|
.main_file = "093_async9.zig",
|
||||||
.output =
|
.output =
|
||||||
\\Main thread continues...
|
\\Main thread continues...
|
||||||
\\Computing on a separate thread!
|
\\Computing on a separate thread!
|
||||||
@@ -1169,7 +1178,7 @@ const exercises = [_]Exercise{
|
|||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "093_async10.zig",
|
.main_file = "094_async10.zig",
|
||||||
.output =
|
.output =
|
||||||
\\Starting critical section...
|
\\Starting critical section...
|
||||||
\\Critical section completed safely.
|
\\Critical section completed safely.
|
||||||
@@ -1177,17 +1186,14 @@ const exercises = [_]Exercise{
|
|||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.main_file = "094_async_quiz.zig",
|
.main_file = "095_quiz_async.zig",
|
||||||
.output = "",
|
|
||||||
.skip = true,
|
|
||||||
},
|
|
||||||
.{
|
|
||||||
.main_file = "095_interfaces.zig",
|
|
||||||
.output =
|
.output =
|
||||||
\\Daily Insect Report:
|
\\=== Doctor Zoraptera's Garden Report ===
|
||||||
\\Ant is alive.
|
\\Temperature : 23C
|
||||||
\\Bee visited 17 flowers.
|
\\Humidity : 63%
|
||||||
\\Grasshopper hopped 32 meters.
|
\\Wind : 13 km/h
|
||||||
|
\\Readings : 9
|
||||||
|
\\Bee-friendly conditions! Expect high pollination.
|
||||||
, // pay attention to the comma
|
, // pay attention to the comma
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
|
|||||||
186
exercises/095_quiz_async.zig
Normal file
186
exercises/095_quiz_async.zig
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
//
|
||||||
|
// Quiz Time — Async I/O!
|
||||||
|
//
|
||||||
|
// Doctor Zoraptera's insect simulation is going well, but she
|
||||||
|
// realized that her virtual garden needs weather data! Insects
|
||||||
|
// behave differently depending on temperature, humidity, and
|
||||||
|
// wind conditions.
|
||||||
|
//
|
||||||
|
// She has set up three weather sensors around the garden that
|
||||||
|
// measure conditions in parallel and report their readings
|
||||||
|
// through a shared data channel. A collector task gathers the
|
||||||
|
// readings, and after all sensors have reported, a garden
|
||||||
|
// report is printed.
|
||||||
|
//
|
||||||
|
// But Doctor Z rushed through the code (she was being chased
|
||||||
|
// by a grasshopper) and left several bugs. Can you fix them?
|
||||||
|
//
|
||||||
|
// Here's what the program should do:
|
||||||
|
// 1. Three sensor tasks run concurrently, each sending
|
||||||
|
// exactly 3 readings through a Queue
|
||||||
|
// 2. A collector task receives readings, protected by a Mutex
|
||||||
|
// 3. After all sensors finish, the queue is closed
|
||||||
|
// 4. The final report is written in a cancel-protected section
|
||||||
|
//
|
||||||
|
// *************************************************************
|
||||||
|
// * A NOTE ABOUT THIS EXERCISE *
|
||||||
|
// * *
|
||||||
|
// * This quiz uses concepts from exercises 084-093. *
|
||||||
|
// * There are 6 bugs to fix — look for the ???s! *
|
||||||
|
// * *
|
||||||
|
// *************************************************************
|
||||||
|
//
|
||||||
|
const std = @import("std");
|
||||||
|
const print = std.debug.print;
|
||||||
|
|
||||||
|
const SensorType = enum { thermometer, hygrometer, anemometer };
|
||||||
|
|
||||||
|
const Reading = struct {
|
||||||
|
sensor_type: SensorType,
|
||||||
|
value: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GardenWeather = struct {
|
||||||
|
temperature: i32 = 0,
|
||||||
|
humidity: i32 = 0,
|
||||||
|
wind: i32 = 0,
|
||||||
|
readings_count: u32 = 0,
|
||||||
|
mutex: std.Io.Mutex = .init,
|
||||||
|
|
||||||
|
fn addReading(self: *GardenWeather, io: std.Io, reading: Reading) void {
|
||||||
|
// Bug 1: The collector needs to lock before modifying
|
||||||
|
// shared state. What Mutex method acquires the lock?
|
||||||
|
self.mutex.lock(io) catch return;
|
||||||
|
self.mutex.???(io) catch return;
|
||||||
|
|
||||||
|
switch (reading.sensor_type) {
|
||||||
|
.thermometer => self.temperature = reading.value,
|
||||||
|
.hygrometer => self.humidity = reading.value,
|
||||||
|
.anemometer => self.wind = reading.value,
|
||||||
|
}
|
||||||
|
self.readings_count += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
const io = init.io;
|
||||||
|
|
||||||
|
var weather = GardenWeather{};
|
||||||
|
|
||||||
|
var reading_buf: [8]Reading = undefined;
|
||||||
|
var queue: std.Io.Queue(Reading) = .init(&reading_buf);
|
||||||
|
|
||||||
|
// Sensor group: runs all three sensors to completion.
|
||||||
|
var sensors: std.Io.Group = .init;
|
||||||
|
|
||||||
|
// Start three sensor tasks. They need GUARANTEED concurrency
|
||||||
|
// since they each simulate real-time measurement.
|
||||||
|
//
|
||||||
|
// Bug 2: io.async doesn't guarantee a separate thread.
|
||||||
|
// Which Io method guarantees true concurrency?
|
||||||
|
// (Don't forget: it can fail, so you need 'try'!)
|
||||||
|
try sensors.???(io, sensor, .{ io, &queue, .thermometer, 20 });
|
||||||
|
try sensors.???(io, sensor, .{ io, &queue, .hygrometer, 60 });
|
||||||
|
try sensors.???(io, sensor, .{ io, &queue, .anemometer, 10 });
|
||||||
|
|
||||||
|
// Collector group: processes readings from the queue.
|
||||||
|
var collectors: std.Io.Group = .init;
|
||||||
|
collectors.async(io, collector, .{ io, &queue, &weather });
|
||||||
|
|
||||||
|
// Bug 3: Wait for ALL sensors to finish sending their readings.
|
||||||
|
// What Group method blocks until all tasks complete?
|
||||||
|
try sensors.await(io);
|
||||||
|
// try sensors.???(io);
|
||||||
|
|
||||||
|
// All sensors done — close the queue so the collector knows
|
||||||
|
// there's no more data coming.
|
||||||
|
queue.close(io);
|
||||||
|
|
||||||
|
// Wait for the collector to drain the queue.
|
||||||
|
try collectors.await(io);
|
||||||
|
|
||||||
|
// Now write the garden report. This is critical — it must
|
||||||
|
// NOT be interrupted, even if something tries to cancel us!
|
||||||
|
//
|
||||||
|
// Bug 4: Protect this section from cancellation.
|
||||||
|
// What Io method swaps the cancel protection state?
|
||||||
|
const old_protection = io.???(.blocked);
|
||||||
|
defer _ = io.???(old_protection);
|
||||||
|
|
||||||
|
printGardenReport(&weather);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sensor(
|
||||||
|
io: std.Io,
|
||||||
|
queue: *std.Io.Queue(Reading),
|
||||||
|
sensor_type: SensorType,
|
||||||
|
base_value: i32,
|
||||||
|
) void {
|
||||||
|
// Each sensor takes exactly 3 measurements.
|
||||||
|
for (1..4) |i| {
|
||||||
|
io.sleep(std.Io.Duration.fromMilliseconds(100), .awake) catch return;
|
||||||
|
|
||||||
|
const reading = Reading{
|
||||||
|
.sensor_type = sensor_type,
|
||||||
|
.value = base_value + @as(i32, @intCast(i)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bug 5: Send the reading into the queue.
|
||||||
|
// What Queue method sends a single element?
|
||||||
|
queue.???(io, reading) catch return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collector(
|
||||||
|
io: std.Io,
|
||||||
|
queue: *std.Io.Queue(Reading),
|
||||||
|
weather: *GardenWeather,
|
||||||
|
) void {
|
||||||
|
while (true) {
|
||||||
|
const reading = queue.getOne(io) catch |err| switch (err) {
|
||||||
|
error.Closed => break,
|
||||||
|
error.Canceled => return,
|
||||||
|
};
|
||||||
|
weather.addReading(io, reading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printGardenReport(weather: *GardenWeather) void {
|
||||||
|
print("=== Doctor Zoraptera's Garden Report ===\n", .{});
|
||||||
|
print("Temperature : {}C\n", .{weather.temperature});
|
||||||
|
print("Humidity : {}%\n", .{weather.humidity});
|
||||||
|
print("Wind : {} km/h\n", .{weather.wind});
|
||||||
|
print("Readings : {}\n", .{weather.readings_count});
|
||||||
|
|
||||||
|
if (weather.temperature > 20 and weather.wind < 15) {
|
||||||
|
print("Bee-friendly conditions! Expect high pollination.\n", .{});
|
||||||
|
} else {
|
||||||
|
print("Grasshoppers will be grumpy today.\n", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Further reading for the curious:
|
||||||
|
//
|
||||||
|
// This quiz covered the main async I/O primitives:
|
||||||
|
// io.async() - launch a task (may run inline)
|
||||||
|
// io.concurrent() - launch with guaranteed parallelism
|
||||||
|
// Group.concurrent() - concurrent tasks in a group
|
||||||
|
// Future.await/cancel - collect or cancel a single task
|
||||||
|
// Group.async/await/cancel - manage fire-and-forget tasks
|
||||||
|
// Select.async/await - race tasks, act on first completion
|
||||||
|
// Queue - bounded channel between tasks
|
||||||
|
// Mutex - protect shared state
|
||||||
|
// CancelProtection - shield critical sections
|
||||||
|
//
|
||||||
|
// There are more synchronization primitives we didn't cover:
|
||||||
|
// Condition - wait for a condition to become true
|
||||||
|
// RwLock - multiple readers OR one writer
|
||||||
|
// Semaphore - limit concurrent access to a resource
|
||||||
|
// Futex - low-level wait/wake on a memory address
|
||||||
|
// Batch - submit multiple I/O operations at once
|
||||||
|
//
|
||||||
|
// The key insight: all of these work through the Io VTable,
|
||||||
|
// so your code is portable across backends (Threaded, Uring,
|
||||||
|
// Kqueue, Dispatch) without any changes!
|
||||||
|
//
|
||||||
|
// Doctor Zoraptera approves.
|
||||||
11
patches/patches/084_interfaces.patch
Normal file
11
patches/patches/084_interfaces.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/084_interfaces.zig 2025-08-15 15:17:57.839348063 +0200
|
||||||
|
+++ answers/084_interfaces.zig 2026-04-03 14:27:32.670756488 +0200
|
||||||
|
@@ -106,7 +106,7 @@
|
||||||
|
for (my_insects) |insect| {
|
||||||
|
// Almost done! We want to print() each insect with a
|
||||||
|
// single method call here.
|
||||||
|
- ???
|
||||||
|
+ insect.print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
11
patches/patches/085_async.patch
Normal file
11
patches/patches/085_async.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/085_async.zig 2026-04-01 20:40:08.904999609 +0200
|
||||||
|
+++ answers/085_async.zig 2026-04-01 20:40:05.641933231 +0200
|
||||||
|
@@ -37,7 +37,7 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
- const io = init.???;
|
||||||
|
+ const io = init.io;
|
||||||
|
|
||||||
|
// Get the current wall-clock time using the Io interface.
|
||||||
|
// Hint: Timestamp.now() takes an Io and a Clock type (.real = wall clock).
|
||||||
14
patches/patches/086_async2.patch
Normal file
14
patches/patches/086_async2.patch
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
--- exercises/086_async2.zig 2026-04-01 19:22:50.017227542 +0200
|
||||||
|
+++ answers/086_async2.zig 2026-04-01 19:21:57.569158481 +0200
|
||||||
|
@@ -38,9 +38,9 @@
|
||||||
|
|
||||||
|
// Now collect the result. What method on Future gives us
|
||||||
|
// the value, blocking if it isn't ready yet?
|
||||||
|
- const answer = future.???(io);
|
||||||
|
+ const answer = future.await(io);
|
||||||
|
|
||||||
|
- std.debug.print("The answer is: {}\n", .{answer});
|
||||||
|
+ std.debug.print("the answer is: {}\n", .{answer});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn computeAnswer(a: u32, b: u32) u32 {
|
||||||
18
patches/patches/087_async3.patch
Normal file
18
patches/patches/087_async3.patch
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
--- exercises/087_async3.zig 2026-04-01 22:51:05.540094851 +0200
|
||||||
|
+++ answers/087_async3.zig 2026-04-01 22:50:44.579669189 +0200
|
||||||
|
@@ -29,12 +29,12 @@
|
||||||
|
const io = init.io;
|
||||||
|
|
||||||
|
// Launch both tasks asynchronously.
|
||||||
|
- var future_a = io.async(slowAdd, .{ 10, 20 });
|
||||||
|
- var future_b = ???(slowMul, .{ 6, 7 });
|
||||||
|
+ var future_a = io.async(slowAdd, .{ 1, 2 });
|
||||||
|
+ var future_b = io.async(slowMul, .{ 6, 7 });
|
||||||
|
|
||||||
|
// Await both results.
|
||||||
|
const sum = future_a.await(io);
|
||||||
|
- const product = future_b.???(io);
|
||||||
|
+ const product = future_b.await(io);
|
||||||
|
|
||||||
|
print("{} + {} = {}\n", .{ 1, 2, sum });
|
||||||
|
print("{} * {} = {}\n", .{ 6, 7, product });
|
||||||
11
patches/patches/088_async4.patch
Normal file
11
patches/patches/088_async4.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/088_async4.zig 2026-04-01 23:17:31.066443941 +0200
|
||||||
|
+++ answers/088_async4.zig 2026-04-01 23:17:39.251612131 +0200
|
||||||
|
@@ -38,7 +38,7 @@
|
||||||
|
|
||||||
|
// Wait for all tasks to finish.
|
||||||
|
// What Group method blocks until all tasks complete?
|
||||||
|
- try group.???
|
||||||
|
+ try group.await(io);
|
||||||
|
|
||||||
|
print("All tasks finished!\n", .{});
|
||||||
|
}
|
||||||
11
patches/patches/089_async5.patch
Normal file
11
patches/patches/089_async5.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/089_async5.zig 2026-04-01 23:40:40.505855238 +0200
|
||||||
|
+++ answers/089_async5.zig 2026-04-01 23:40:10.176236971 +0200
|
||||||
|
@@ -40,7 +40,7 @@
|
||||||
|
|
||||||
|
// We don't want to wait 10 seconds!
|
||||||
|
// Which Future method requests cancellation AND returns the result?
|
||||||
|
- const result = ???;
|
||||||
|
+ const result = future.cancel(io);
|
||||||
|
|
||||||
|
print("Task returned: {}\n", .{result});
|
||||||
|
}
|
||||||
11
patches/patches/090_async6.patch
Normal file
11
patches/patches/090_async6.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/090_async6.zig 2026-04-02 10:25:34.016616118 +0200
|
||||||
|
+++ answers/090_async6.zig 2026-04-02 10:27:48.827144051 +0200
|
||||||
|
@@ -47,7 +47,7 @@
|
||||||
|
|
||||||
|
// Wait for the first finisher.
|
||||||
|
// What Select method returns the first completed result?
|
||||||
|
- const winner = ???;
|
||||||
|
+ const winner = try sel.await();
|
||||||
|
|
||||||
|
switch (winner) {
|
||||||
|
.hare => |msg| print("Hare: {s}\n", .{msg}),
|
||||||
13
patches/patches/091_async7.patch
Normal file
13
patches/patches/091_async7.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
--- exercises/091_async7.zig 2026-04-02 10:50:08.142508099 +0200
|
||||||
|
+++ answers/091_async7.zig 2026-04-02 10:49:59.629341593 +0200
|
||||||
|
@@ -49,8 +49,8 @@
|
||||||
|
for (0..times) |_| {
|
||||||
|
// Acquire the lock before modifying shared state.
|
||||||
|
// What Mutex method blocks until the lock is acquired?
|
||||||
|
- state.mutex.??? catch return;
|
||||||
|
- defer state.mutex.unlock(); // <-- what's missing here?
|
||||||
|
+ state.mutex.lock(io) catch return;
|
||||||
|
+ defer state.mutex.unlock(io);
|
||||||
|
|
||||||
|
state.counter += 1;
|
||||||
|
}
|
||||||
11
patches/patches/092_async8.patch
Normal file
11
patches/patches/092_async8.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/092_async8.zig 2026-04-02 10:49:27.925721496 +0200
|
||||||
|
+++ answers/092_async8.zig 2026-04-02 10:49:31.694795212 +0200
|
||||||
|
@@ -43,7 +43,7 @@
|
||||||
|
// 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;
|
||||||
|
+ queue.putOne(io, @intCast(i)) catch return;
|
||||||
|
}
|
||||||
|
// Signal that we're done sending.
|
||||||
|
queue.close(io);
|
||||||
11
patches/patches/093_async9.patch
Normal file
11
patches/patches/093_async9.patch
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
--- exercises/093_async9.zig 2026-04-03 13:44:50.526780809 +0200
|
||||||
|
+++ answers/093_async9.zig 2026-04-03 13:44:54.957870294 +0200
|
||||||
|
@@ -36,7 +36,7 @@
|
||||||
|
// Launch with a guaranteed separate thread.
|
||||||
|
// Which Io method guarantees true concurrency?
|
||||||
|
// (Hint: unlike io.async, this one can fail!)
|
||||||
|
- var future = try io.???(compute, .{io});
|
||||||
|
+ var future = try io.concurrent(compute, .{io});
|
||||||
|
|
||||||
|
print("Main thread continues...\n", .{});
|
||||||
|
|
||||||
13
patches/patches/094_async10.patch
Normal file
13
patches/patches/094_async10.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
--- exercises/094_async10.zig 2026-04-03 14:25:16.600025924 +0200
|
||||||
|
+++ answers/094_async10.zig 2026-04-03 14:24:56.192615893 +0200
|
||||||
|
@@ -50,8 +50,8 @@
|
||||||
|
|
||||||
|
// Protect this section from cancellation.
|
||||||
|
// What method swaps the cancel protection state?
|
||||||
|
- const old = io.???(. blocked);
|
||||||
|
- defer _ = io.???(old);
|
||||||
|
+ const old = io.swapCancelProtection(.blocked);
|
||||||
|
+ defer _ = io.swapCancelProtection(old);
|
||||||
|
|
||||||
|
// This sleep will NOT return error.Canceled even though
|
||||||
|
// we get canceled during it — protection is active!
|
||||||
52
patches/patches/095_quiz_async.patch
Normal file
52
patches/patches/095_quiz_async.patch
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
--- exercises/095_quiz_async.zig 2026-04-03 18:04:53.577391455 +0200
|
||||||
|
+++ answers/095_quiz_async.zig 2026-04-03 18:05:42.570392172 +0200
|
||||||
|
@@ -51,7 +51,7 @@
|
||||||
|
// Bug 1: The collector needs to lock before modifying
|
||||||
|
// shared state. What Mutex method acquires the lock?
|
||||||
|
self.mutex.lock(io) catch return;
|
||||||
|
- self.mutex.???(io) catch return;
|
||||||
|
+ defer self.mutex.unlock(io);
|
||||||
|
|
||||||
|
switch (reading.sensor_type) {
|
||||||
|
.thermometer => self.temperature = reading.value,
|
||||||
|
@@ -79,9 +79,9 @@
|
||||||
|
// Bug 2: io.async doesn't guarantee a separate thread.
|
||||||
|
// Which Io method guarantees true concurrency?
|
||||||
|
// (Don't forget: it can fail, so you need 'try'!)
|
||||||
|
- try sensors.???(io, sensor, .{ io, &queue, .thermometer, 20 });
|
||||||
|
- try sensors.???(io, sensor, .{ io, &queue, .hygrometer, 60 });
|
||||||
|
- try sensors.???(io, sensor, .{ io, &queue, .anemometer, 10 });
|
||||||
|
+ try sensors.concurrent(io, sensor, .{ io, &queue, .thermometer, 20 });
|
||||||
|
+ try sensors.concurrent(io, sensor, .{ io, &queue, .hygrometer, 60 });
|
||||||
|
+ try sensors.concurrent(io, sensor, .{ io, &queue, .anemometer, 10 });
|
||||||
|
|
||||||
|
// Collector group: processes readings from the queue.
|
||||||
|
var collectors: std.Io.Group = .init;
|
||||||
|
@@ -90,7 +90,6 @@
|
||||||
|
// Bug 3: Wait for ALL sensors to finish sending their readings.
|
||||||
|
// What Group method blocks until all tasks complete?
|
||||||
|
try sensors.await(io);
|
||||||
|
- // try sensors.???(io);
|
||||||
|
|
||||||
|
// All sensors done — close the queue so the collector knows
|
||||||
|
// there's no more data coming.
|
||||||
|
@@ -104,8 +103,8 @@
|
||||||
|
//
|
||||||
|
// Bug 4: Protect this section from cancellation.
|
||||||
|
// What Io method swaps the cancel protection state?
|
||||||
|
- const old_protection = io.???(.blocked);
|
||||||
|
- defer _ = io.???(old_protection);
|
||||||
|
+ const old_protection = io.swapCancelProtection(.blocked);
|
||||||
|
+ defer _ = io.swapCancelProtection(old_protection);
|
||||||
|
|
||||||
|
printGardenReport(&weather);
|
||||||
|
}
|
||||||
|
@@ -127,7 +126,7 @@
|
||||||
|
|
||||||
|
// Bug 5: Send the reading into the queue.
|
||||||
|
// What Queue method sends a single element?
|
||||||
|
- queue.???(io, reading) catch return;
|
||||||
|
+ queue.putOne(io, reading) catch return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user