34 : tokens_(static_cast<
std::int64_t>(burst_size) * PRECISION_FACTOR)
35 , max_tokens_(static_cast<
std::int64_t>(burst_size) * PRECISION_FACTOR)
36 , refill_rate_(static_cast<double>(tokens_per_second) * PRECISION_FACTOR / 1e9)
37 , last_refill_(
std::chrono::steady_clock::now().time_since_epoch().count())
59 auto now = std::chrono::steady_clock::now().time_since_epoch().count();
60 auto last = last_refill_.load(std::memory_order_acquire);
63 auto elapsed_ns = now - last;
70 if (!last_refill_.compare_exchange_weak(
72 std::memory_order_acq_rel,
73 std::memory_order_relaxed))
80 double rate = refill_rate_.load(std::memory_order_relaxed);
81 auto new_tokens =
static_cast<std::int64_t
>(elapsed_ns * rate);
89 std::int64_t max = max_tokens_.load(std::memory_order_relaxed);
90 std::int64_t current = tokens_.load(std::memory_order_relaxed);
91 std::int64_t updated = std::min(current + new_tokens, max);
94 tokens_.compare_exchange_weak(
96 std::memory_order_relaxed,
97 std::memory_order_relaxed);
123 std::int64_t needed =
static_cast<std::int64_t
>(tokens) * PRECISION_FACTOR;
126 std::int64_t current = tokens_.load(std::memory_order_acquire);
127 while (current >= needed)
129 if (tokens_.compare_exchange_weak(
130 current, current - needed,
131 std::memory_order_acq_rel,
132 std::memory_order_acquire))
163 std::chrono::milliseconds timeout) ->
bool
165 auto deadline = std::chrono::steady_clock::now() + timeout;
168 auto backoff = std::chrono::microseconds{1};
169 constexpr auto max_backoff = std::chrono::milliseconds{1};
171 while (std::chrono::steady_clock::now() < deadline)
173 if (try_acquire(tokens))
179 std::this_thread::sleep_for(backoff);
184 std::chrono::duration_cast<std::chrono::microseconds>(max_backoff));
188 return try_acquire(tokens);
206 std::int64_t current =
tokens_.load(std::memory_order_acquire);
226 -> std::chrono::nanoseconds
230 std::int64_t needed =
static_cast<std::int64_t
>(tokens) * PRECISION_FACTOR;
231 std::int64_t current = tokens_.load(std::memory_order_acquire);
233 if (current >= needed)
235 return std::chrono::nanoseconds{0};
239 std::int64_t deficit = needed - current;
242 double rate = refill_rate_.load(std::memory_order_relaxed);
246 return std::chrono::nanoseconds::max();
249 auto wait_ns =
static_cast<std::int64_t
>(deficit / rate);
250 return std::chrono::nanoseconds{wait_ns};
269 double new_rate =
static_cast<double>(tokens_per_second) * PRECISION_FACTOR / 1e9;
270 refill_rate_.store(new_rate, std::memory_order_release);
284 std::int64_t new_max =
static_cast<std::int64_t
>(burst_size) * PRECISION_FACTOR;
285 max_tokens_.store(new_max, std::memory_order_release);
288 std::int64_t current = tokens_.load(std::memory_order_acquire);
289 while (current > new_max)
291 if (tokens_.compare_exchange_weak(
293 std::memory_order_acq_rel,
294 std::memory_order_acquire))
307 double rate =
refill_rate_.load(std::memory_order_acquire);
318 std::int64_t max =
max_tokens_.load(std::memory_order_acquire);
332 std::int64_t max = max_tokens_.load(std::memory_order_acquire);
333 tokens_.store(max, std::memory_order_release);
335 std::chrono::steady_clock::now().time_since_epoch().count(),
336 std::memory_order_release);
Lock-free token bucket rate limiter for controlling throughput.
auto get_rate() const -> std::size_t
Returns the current refill rate.
std::atomic< std::int64_t > max_tokens_
Maximum tokens (burst size) scaled by precision factor.
auto try_acquire_for(std::size_t tokens, std::chrono::milliseconds timeout) -> bool
Attempts to acquire tokens with a timeout.
token_bucket(std::size_t tokens_per_second, std::size_t burst_size)
Constructs a token bucket with the specified rate and burst size.
auto time_until_available(std::size_t tokens) const -> std::chrono::nanoseconds
Calculates time until the specified tokens become available.
auto get_burst_size() const -> std::size_t
Returns the maximum bucket capacity.
std::atomic< double > refill_rate_
Token refill rate in nano-tokens per nanosecond.
std::atomic< std::int64_t > tokens_
Current token count (scaled by 1000 for sub-token precision).
auto available_tokens() const -> std::size_t
Returns the current number of available tokens.
auto set_burst_size(std::size_t burst_size) -> void
Updates the maximum bucket capacity.
auto reset() -> void
Resets the bucket to full capacity.
auto refill() -> void
Refills tokens based on elapsed time since last refill.
auto try_acquire(std::size_t tokens=1) -> bool
Attempts to acquire tokens without waiting.
static constexpr std::int64_t PRECISION_FACTOR
Precision factor for fixed-point token calculations.
auto set_rate(std::size_t tokens_per_second) -> void
Updates the token refill rate.
Core threading foundation of the thread system library.
Lock-free token bucket rate limiter for controlling throughput.