| ... | @@ -1,22 +1,34 @@ | ... | @@ -1,22 +1,34 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const WaitGroup = @This(); | 2 | const WaitGroup = @This(); |
| 3 | | 3 | |
| | 4 | lock: std.Mutex = .{}, |
| 4 | counter: usize = 0, | 5 | counter: usize = 0, |
| 5 | event: ?*std.AutoResetEvent = null, | 6 | event: std.AutoResetEvent = .{}, |
| 6 | | 7 | |
| 7 | pub fn start(self: *WaitGroup) void { | 8 | pub fn start(self: *WaitGroup) void { |
| 8 | _ = @atomicRmw(usize, &self.counter, .Add, 1, .SeqCst); | 9 | const held = self.lock.acquire(); |
| | 10 | defer held.release(); |
| | 11 | |
| | 12 | self.counter += 1; |
| 9 | } | 13 | } |
| 10 | | 14 | |
| 11 | pub fn stop(self: *WaitGroup) void { | 15 | pub fn stop(self: *WaitGroup) void { |
| 12 | if (@atomicRmw(usize, &self.counter, .Sub, 1, .SeqCst) == 1) | 16 | const held = self.lock.acquire(); |
| 13 | if (@atomicRmw(?*std.AutoResetEvent, &self.event, .Xchg, null, .SeqCst)) |event| | 17 | defer held.release(); |
| 14 | event.set(); | 18 | |
| | 19 | self.counter -= 1; |
| | 20 | if (self.counter == 0) |
| | 21 | self.event.set(); |
| 15 | } | 22 | } |
| 16 | | 23 | |
| 17 | pub fn wait(self: *WaitGroup) void { | 24 | pub fn wait(self: *WaitGroup) void { |
| 18 | var event = std.AutoResetEvent{}; | 25 | { |
| 19 | @atomicStore(?*std.AutoResetEvent, &self.event, &event, .SeqCst); | 26 | const held = self.lock.acquire(); |
| 20 | if (@atomicLoad(usize, &self.counter, .SeqCst) != 0) | 27 | defer held.release(); |
| 21 | event.wait(); | 28 | |
| | 29 | if (self.counter == 0) |
| | 30 | return; |
| | 31 | } |
| | 32 | |
| | 33 | self.event.wait(); |
| 22 | } | 34 | } |