VLink 2.0.0
A high-performance communication middleware
Loading...
Searching...
No Matches
semaphore.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 * Author: Thun Lu <thun.lu@zohomail.cn>
4 * Repo: https://github.com/thun-res/vlink
5 * _ __ __ _ __
6 * | | / / / / (_) ____ / /__
7 * | | / / / / / / / __ \ / //_/
8 * | |/ / / /___ / / / / / / / ,<
9 * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24/**
25 * @file semaphore.h
26 * @brief In-process counting semaphore with optional timeout.
27 *
28 * @details
29 * @c Semaphore provides classic P/V (acquire/release) semaphore semantics
30 * within a single process. It is built on @c std::mutex and @c std::condition_variable
31 * (via the VLink @c ConditionVariable, which uses @c CLOCK_MONOTONIC to avoid NTP
32 * clock-jump issues on Linux).
33 *
34 * Typical use cases:
35 * - Limiting concurrent access to a resource pool.
36 * - Signalling between a producer and one or more consumers.
37 * - Throttling task submission to a bounded work queue.
38 *
39 * @note
40 * - @c acquire() blocks the caller until at least @p n permits are available.
41 * - @c release() is safe to call from any thread, including signal handlers
42 * (as long as the underlying @c std::mutex is signal-safe on the platform).
43 * - @c reset() with @p interrupt_waiters == @c true is a disruptive operation
44 * that wakes all blocked @c acquire() callers and returns @c false to them.
45 * Use it only during controlled shutdown.
46 * - This is an in-process semaphore. For cross-process synchronisation, use
47 * @c SysSemaphore.
48 *
49 * @par Example
50 * @code
51 * vlink::Semaphore sem(0); // start at 0
52 *
53 * // Producer:
54 * do_work();
55 * sem.release(); // signal one consumer
56 *
57 * // Consumer:
58 * if (sem.acquire(1, 100)) { // wait up to 100 ms
59 * consume_result();
60 * } else {
61 * handle_timeout();
62 * }
63 * @endcode
64 */
65
66#pragma once
67
68#include <memory>
69
70#include "./macros.h"
71
72namespace vlink {
73
74/**
75 * @class Semaphore
76 * @brief In-process counting semaphore with optional acquire timeout.
77 *
78 * @details
79 * The internal counter is initialised via the constructor and can be
80 * atomically decremented (@c acquire) or incremented (@c release).
81 */
83 public:
84 /**
85 * @brief Sentinel value for @c acquire() meaning "wait indefinitely".
86 */
87 static constexpr int kInfinite{-1};
88
89 /**
90 * @brief Constructs a @c Semaphore with an initial counter value.
91 *
92 * @param count Initial number of available permits (default: 0).
93 */
94 explicit Semaphore(size_t count = 0) noexcept;
95
96 /**
97 * @brief Destructor. Wakes all blocked acquirers before destruction.
98 */
99 ~Semaphore() noexcept;
100
101 /**
102 * @brief Decrements the semaphore counter by @p n, blocking until permits
103 * are available.
104 *
105 * @details
106 * If the counter is less than @p n, the caller is blocked until enough
107 * @c release() calls bring the counter up. A timeout causes the function
108 * to return @c false without decrementing the counter.
109 *
110 * @param n Number of permits to acquire (default: 1).
111 * @param timeout_ms Maximum time to wait in milliseconds.
112 * Use @c kInfinite (-1) to wait indefinitely (default).
113 * @return @c true if the permits were acquired, @c false on timeout or
114 * if the semaphore was reset with @p interrupt_waiters == @c true.
115 */
116 bool acquire(size_t n = 1, int timeout_ms = kInfinite) noexcept;
117
118 /**
119 * @brief Increments the semaphore counter by @p n, waking blocked acquirers.
120 *
121 * @details
122 * If threads are blocked in @c acquire(), they are notified.
123 * The notification is delivered to at most @p n waiting threads.
124 *
125 * @param n Number of permits to release (default: 1).
126 */
127 void release(size_t n = 1) noexcept;
128
129 /**
130 * @brief Resets the semaphore counter to zero.
131 *
132 * @details
133 * If @p interrupt_waiters is @c true, all threads blocked in @c acquire()
134 * are woken and their calls return @c false. Use this during shutdown to
135 * unblock consumers cleanly.
136 *
137 * @param interrupt_waiters If @c true, wake all blocked acquirers (default: false).
138 */
139 void reset(bool interrupt_waiters = false) noexcept;
140
141 /**
142 * @brief Returns the current value of the semaphore counter.
143 *
144 * @details
145 * The returned value is a snapshot; it may change before the caller can use it.
146 * Intended for diagnostic and logging purposes only.
147 *
148 * @return Current counter value.
149 */
150 [[nodiscard]] size_t get_count() const noexcept;
151
152 private:
153 std::unique_ptr<struct SemaphoreImpl> impl_;
154
156};
157
158} // namespace vlink
Platform-independent macro definitions for the VLink library.
#define VLINK_EXPORT
Definition macros.h:85
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition macros.h:184
STL namespace.