| File: System\Diagnostics\RateLimiter.cs | Web Access |
| Project: src\runtime\src\libraries\System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj (System.Diagnostics.DiagnosticSource) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Threading; namespace System.Diagnostics { /// <summary> /// A class that limits operations to a maximum count per second. /// </summary> internal sealed class RateLimiter { private readonly int _maxOperationsPerSecond; private readonly Stopwatch _stopwatch; private readonly long _ticksPerSecond; private int _currentOperationCount; private long _intervalStartTicks; /// <summary> /// Initializes a new instance of the RateLimiter class. /// </summary> /// <param name="maxOperationsPerSecond">Maximum number of operations allowed per second.</param> internal RateLimiter(int maxOperationsPerSecond) { Debug.Assert(maxOperationsPerSecond > 0, "maxOperationsPerSecond must be greater than 0"); _maxOperationsPerSecond = maxOperationsPerSecond; _stopwatch = new Stopwatch(); _stopwatch.Start(); _intervalStartTicks = _stopwatch.ElapsedTicks; _currentOperationCount = 0; _ticksPerSecond = Stopwatch.Frequency; } /// <summary> /// Tries to perform an operation if the rate limit allows it. /// </summary> /// <returns>True if the operation is allowed within the rate limit, otherwise false.</returns> internal bool TryAcquire() { do { long currentTicks = _stopwatch.ElapsedTicks; long intervalStartTicks = Interlocked.Read(ref _intervalStartTicks); int currentOperationCount = Volatile.Read(ref _currentOperationCount); long elapsedTicks = currentTicks - intervalStartTicks; // If a second has elapsed, reset the counter if (elapsedTicks >= _ticksPerSecond) { if (Interlocked.CompareExchange(ref _currentOperationCount, 1, currentOperationCount) != currentOperationCount) { // Another thread has already reset the counter, so we need to check again continue; } // Update the _intervalStartTicks if no-one else updated it in the meantime. Interlocked.CompareExchange(ref _intervalStartTicks, currentTicks, intervalStartTicks); return true; // Allow the operation } return Interlocked.Increment(ref _currentOperationCount) <= _maxOperationsPerSecond; } while (true); } } }