Commit 8addf53fb5

Felix Kollmann <mail@fkollmann.de>
2024-02-13 18:51:42
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 parent d7563a7
Changed files (1)
lib
std
lib/std/Thread/Semaphore.zig
@@ -1,6 +1,23 @@
 //! A semaphore is an unsigned integer that blocks the kernel thread if
 //! the number would become negative.
 //! This API supports static initialization and does not require deinitialization.
+//!
+//! Example:
+//! ```
+//! var s = Semaphore{};
+//!
+//! fn consumer() void {
+//!     s.wait();
+//! }
+//!
+//! fn producer() void {
+//!     s.post();
+//! }
+//!
+//! const thread = try std.Thread.spawn(.{}, producer, .{});
+//! consumer();
+//! thread.join();
+//! ```
 
 mutex: Mutex = .{},
 cond: Condition = .{},
@@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void {
         sem.cond.signal();
 }
 
+pub fn timedWait(sem: *Semaphore, timeout_ns: u64) error{Timeout}!void {
+    var timeout_timer = std.time.Timer.start() catch unreachable;
+
+    sem.mutex.lock();
+    defer sem.mutex.unlock();
+
+    while (sem.permits == 0) {
+        const elapsed = timeout_timer.read();
+        if (elapsed > timeout_ns)
+            return error.Timeout;
+
+        const local_timeout_ns = timeout_ns - elapsed;
+        try sem.cond.timedWait(&sem.mutex, local_timeout_ns);
+    }
+
+    sem.permits -= 1;
+    if (sem.permits > 0)
+        sem.cond.signal();
+}
+
 pub fn post(sem: *Semaphore) void {
     sem.mutex.lock();
     defer sem.mutex.unlock();
@@ -59,3 +96,16 @@ test "Thread.Semaphore" {
     sem.wait();
     try testing.expect(n == num_threads);
 }
+
+test "Thread.Semaphore - timedWait" {
+    var sem = Semaphore{};
+    try testing.expectEqual(0, sem.permits);
+
+    try testing.expectError(error.Timeout, sem.timedWait(1));
+
+    sem.post();
+    try testing.expectEqual(1, sem.permits);
+
+    try sem.timedWait(1);
+    try testing.expectEqual(0, sem.permits);
+}