authorgravatar for mail@fkollmann.deFelix Kollmann <mail@fkollmann.de> 2024-02-13 18:51:42+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-13 11:51:42-06:00
log8addf53fb5046a65c6fd0c0d2e7894be60468132
tree189044c1a1adb79047ff8bdb892193ebd78f2778
parentd7563a7753393d7f0d1af445276a64b8a55cb857
signaturebadge-check Signed by PGP key B5690EEEBB952194

Add `timedWait` to `std.Thread.Semaphore` (#18805)

* Add `timedWait` to `std.Thread.Semaphore` Add example to documentation of `std.Thread.Semaphore` * Add unit test for thread semaphore timed wait Fix missing try * Change unit test to be simpler * Change `timedWait()` to keep a deadline * Change `timedWait()` to return earlier in some scenarios * Change `timedWait()` to keep a deadline (based on std.Timer) (similar to std.Thread.Futex) --------- Co-authored-by: protty <45520026+kprotty@users.noreply.github.com>

1 files changed, 50 insertions(+), 0 deletions(-)

lib/std/Thread/Semaphore.zig+50
...@@ -1,6 +1,23 @@...@@ -1,6 +1,23 @@
1//! A semaphore is an unsigned integer that blocks the kernel thread if1//! A semaphore is an unsigned integer that blocks the kernel thread if
2//! the number would become negative.2//! the number would become negative.
3//! This API supports static initialization and does not require deinitialization.3//! This API supports static initialization and does not require deinitialization.
4//!
5//! Example:
6//! ```
7//! var s = Semaphore{};
8//!
9//! fn consumer() void {
10//! s.wait();
11//! }
12//!
13//! fn producer() void {
14//! s.post();
15//! }
16//!
17//! const thread = try std.Thread.spawn(.{}, producer, .{});
18//! consumer();
19//! thread.join();
20//! ```
421
5mutex: Mutex = .{},22mutex: Mutex = .{},
6cond: Condition = .{},23cond: Condition = .{},
...@@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void {...@@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void {
26 sem.cond.signal();43 sem.cond.signal();
27}44}
2845
46pub fn timedWait(sem: *Semaphore, timeout_ns: u64) error{Timeout}!void {
47 var timeout_timer = std.time.Timer.start() catch unreachable;
48
49 sem.mutex.lock();
50 defer sem.mutex.unlock();
51
52 while (sem.permits == 0) {
53 const elapsed = timeout_timer.read();
54 if (elapsed > timeout_ns)
55 return error.Timeout;
56
57 const local_timeout_ns = timeout_ns - elapsed;
58 try sem.cond.timedWait(&sem.mutex, local_timeout_ns);
59 }
60
61 sem.permits -= 1;
62 if (sem.permits > 0)
63 sem.cond.signal();
64}
65
29pub fn post(sem: *Semaphore) void {66pub fn post(sem: *Semaphore) void {
30 sem.mutex.lock();67 sem.mutex.lock();
31 defer sem.mutex.unlock();68 defer sem.mutex.unlock();
...@@ -59,3 +96,16 @@ test "Thread.Semaphore" {...@@ -59,3 +96,16 @@ test "Thread.Semaphore" {
59 sem.wait();96 sem.wait();
60 try testing.expect(n == num_threads);97 try testing.expect(n == num_threads);
61}98}
99
100test "Thread.Semaphore - timedWait" {
101 var sem = Semaphore{};
102 try testing.expectEqual(0, sem.permits);
103
104 try testing.expectError(error.Timeout, sem.timedWait(1));
105
106 sem.post();
107 try testing.expectEqual(1, sem.permits);
108
109 try sem.timedWait(1);
110 try testing.expectEqual(0, sem.permits);
111}