From 8f0cc17d90ffa8df21efb867bfdc23736e6e614e Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Thu, 11 Dec 2025 21:46:07 +0100 Subject: [PATCH] PoolingSemaphore optimized. --- PerfectNumbers.Core/PollingSemaphore.cs | 138 +++++++++++------------- 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/PerfectNumbers.Core/PollingSemaphore.cs b/PerfectNumbers.Core/PollingSemaphore.cs index 04aed76..3259b9e 100644 --- a/PerfectNumbers.Core/PollingSemaphore.cs +++ b/PerfectNumbers.Core/PollingSemaphore.cs @@ -9,95 +9,83 @@ namespace PerfectNumbers.Core; /// public sealed class PollingSemaphore { - private readonly int _maximumConcurrency; - private readonly TimeSpan _pauseBetweenChecks; - private readonly bool _hasPause; - private int _currentHolders; + private readonly int _maximumConcurrency; + private readonly TimeSpan _pauseBetweenChecks; + private readonly bool _hasPause; + private int _currentHolders; - public PollingSemaphore(int maximumConcurrency, TimeSpan pauseBetweenChecks) - { - if (maximumConcurrency <= 0) - { - throw new ArgumentOutOfRangeException(nameof(maximumConcurrency)); - } + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public PollingSemaphore(int maximumConcurrency, TimeSpan pauseBetweenChecks) + { + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(maximumConcurrency, 0); + ArgumentOutOfRangeException.ThrowIfLessThan(pauseBetweenChecks, TimeSpan.Zero); - if (pauseBetweenChecks < TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException(nameof(pauseBetweenChecks)); - } + _maximumConcurrency = maximumConcurrency; + _pauseBetweenChecks = pauseBetweenChecks; + _hasPause = pauseBetweenChecks > TimeSpan.Zero; + } - _maximumConcurrency = maximumConcurrency; - _pauseBetweenChecks = pauseBetweenChecks; - _hasPause = pauseBetweenChecks > TimeSpan.Zero; - } + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public bool TryEnter() + { + int newValue = Interlocked.Increment(ref _currentHolders); + if (newValue <= _maximumConcurrency) + { + return true; + } - public bool TryEnter() - { - int newValue = Interlocked.Increment(ref _currentHolders); + Interlocked.Decrement(ref _currentHolders); + return false; + } - if (newValue <= _maximumConcurrency) - { - return true; - } - - Interlocked.Decrement(ref _currentHolders); - return false; - } - - public bool Wait(TimeSpan timeout, CancellationToken cancellationToken = default) - { + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public bool Wait(TimeSpan timeout, CancellationToken cancellationToken = default) + { ArgumentOutOfRangeException.ThrowIfLessThan(timeout, Timeout.InfiniteTimeSpan); - Stopwatch? stopwatch = timeout == Timeout.InfiniteTimeSpan ? null : Stopwatch.StartNew(); - SpinWait spinner = new(); + bool hasPause = _hasPause; + bool hasStopwatch = timeout != Timeout.InfiniteTimeSpan; + SpinWait spinner = new(); + TimeSpan pauseBetweenChecks = _pauseBetweenChecks; + Stopwatch? stopwatch = hasStopwatch ? Stopwatch.StartNew() : null; + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); - while (true) - { - cancellationToken.ThrowIfCancellationRequested(); + if (TryEnter()) + { + return true; + } - if (TryEnter()) - { - return true; - } + if (hasStopwatch && stopwatch!.Elapsed >= timeout) + { + return false; + } - if (stopwatch is not null && stopwatch.Elapsed >= timeout) - { - return false; - } + if (spinner.Count < 10) + { + spinner.SpinOnce(); + continue; + } - if (spinner.Count < 10) - { - spinner.SpinOnce(); - continue; - } + if (hasPause) + { + Thread.Sleep(pauseBetweenChecks); + spinner.Reset(); + } + else + { + Thread.Yield(); + } + } + } - if (_hasPause) - { - Thread.Sleep(_pauseBetweenChecks); - spinner.Reset(); - } - else - { - Thread.Yield(); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public bool Wait(CancellationToken cancellationToken) => Wait(Timeout.InfiniteTimeSpan, cancellationToken); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public bool Wait() => Wait(Timeout.InfiniteTimeSpan, CancellationToken.None); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Release() - { - int newValue = Interlocked.Decrement(ref _currentHolders); - - if (newValue < 0) - { - Interlocked.Increment(ref _currentHolders); - throw new SynchronizationLockException("Release called more times than Wait."); - } - } + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public void Release() => _ = Interlocked.Decrement(ref _currentHolders); }