Skip to content

Commit

Permalink
09-threads.md - add basic mutex and waiting demonstration
Browse files Browse the repository at this point in the history
Add a basic example extending the existing one:

* Uses the same sleepy function
* Adds a global integer counter
* Adds use of a mutex example
* Adds use of a wait group and thread pool for waiting for completions
* Uses defer on mutex and waitgroup as good practice demonstration

Issues

* uses a `sleep()` to avoid reaching the `waitAndWork(&wg)` too soon. Feels like a hack, but not sure what else to do.

Tested with

* `0.13.0`
* `0.14.0-dev.2441+3670910f2`
  • Loading branch information
taikedz authored Dec 12, 2024
1 parent 08afb41 commit ac1632d
Showing 1 changed file with 66 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,69 @@ test "threading" {

Threads, however, aren't particularly useful without strategies for thread
safety.

## A simple example with a sleepy function and a shared counter

```zig
const std = @import("std");
const Thread = std.Thread;
var LINE:u8 = 0;
fn sleepy(name:[]const u8, steps:u8, mut:*Thread.Mutex, wg:*Thread.WaitGroup) void {
var i:u8 = 0;
wg.start();
defer wg.finish();
while (i < steps) {
std.time.sleep(1 * std.time.ns_per_s);
{
mut.lock();
defer mut.unlock();
LINE += 1;
i += 1;
std.debug.print("{d} {s}\n", .{LINE, name});
}
}
}
pub fn main() !void {
// ----- Memory
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
// ----- Thread safety wrapping
var tsafe_allocator: std.heap.ThreadSafeAllocator = .{
.child_allocator = gpa.allocator(),
};
const alloc = tsafe_allocator.allocator();
// To wait on threads we need a waitgroup, and a thread pool
// to wrap the waitgroup.
var wg:Thread.WaitGroup = undefined;
wg.reset();
var pool:Thread.Pool = undefined;
try pool.init(.{.allocator = alloc});
defer pool.deinit();
// A mutex to ensure we don't write the counter simultaneously
var mut:Thread.Mutex = undefined;
// Use OS Thread spawning, pass in a function, and the arguments to pass
// down to it in an anonymous struct
_ = try std.Thread.spawn(.{}, sleepy, .{"One", 1, &mut, &wg});
_ = try std.Thread.spawn(.{}, sleepy, .{"Two", 2, &mut, &wg});
// Wait a little for a thread to call .start() - sometimes we get to the waitgroup
// here and see it empty... before any thread acquires it ...!!
std.time.sleep(1 * std.time.ns_per_s);
pool.waitAndWork(&wg);
std.debug.print("Finished.\n", .{});
}
```

0 comments on commit ac1632d

Please sign in to comment.