PoolingSemaphore optimized.

This commit is contained in:
mlemanczyk committed 2025-12-11 21:46:07 +01:00
1 parent 60ccb3db74
commit 8f0cc17d90
1 file changed
+63 -75
+63 -75
View File
@@ -9,95 +9,83 @@ namespace PerfectNumbers.Core;
/// </summary> /// </summary>
public sealed class PollingSemaphore public sealed class PollingSemaphore
{ {
private readonly int _maximumConcurrency; private readonly int _maximumConcurrency;
private readonly TimeSpan _pauseBetweenChecks; private readonly TimeSpan _pauseBetweenChecks;
private readonly bool _hasPause; private readonly bool _hasPause;
private int _currentHolders; private int _currentHolders;
public PollingSemaphore(int maximumConcurrency, TimeSpan pauseBetweenChecks) [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
{ public PollingSemaphore(int maximumConcurrency, TimeSpan pauseBetweenChecks)
if (maximumConcurrency <= 0) {
{ ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(maximumConcurrency, 0);
throw new ArgumentOutOfRangeException(nameof(maximumConcurrency)); ArgumentOutOfRangeException.ThrowIfLessThan(pauseBetweenChecks, TimeSpan.Zero);
}
if (pauseBetweenChecks < TimeSpan.Zero) _maximumConcurrency = maximumConcurrency;
{ _pauseBetweenChecks = pauseBetweenChecks;
throw new ArgumentOutOfRangeException(nameof(pauseBetweenChecks)); _hasPause = pauseBetweenChecks > TimeSpan.Zero;
} }
_maximumConcurrency = maximumConcurrency; [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
_pauseBetweenChecks = pauseBetweenChecks; public bool TryEnter()
_hasPause = pauseBetweenChecks > TimeSpan.Zero; {
} int newValue = Interlocked.Increment(ref _currentHolders);
if (newValue <= _maximumConcurrency)
{
return true;
}
public bool TryEnter() Interlocked.Decrement(ref _currentHolders);
{ return false;
int newValue = Interlocked.Increment(ref _currentHolders); }
if (newValue <= _maximumConcurrency) [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
{ public bool Wait(TimeSpan timeout, CancellationToken cancellationToken = default)
return true; {
}
Interlocked.Decrement(ref _currentHolders);
return false;
}
public bool Wait(TimeSpan timeout, CancellationToken cancellationToken = default)
{
ArgumentOutOfRangeException.ThrowIfLessThan(timeout, Timeout.InfiniteTimeSpan); ArgumentOutOfRangeException.ThrowIfLessThan(timeout, Timeout.InfiniteTimeSpan);
Stopwatch? stopwatch = timeout == Timeout.InfiniteTimeSpan ? null : Stopwatch.StartNew(); bool hasPause = _hasPause;
SpinWait spinner = new(); bool hasStopwatch = timeout != Timeout.InfiniteTimeSpan;
SpinWait spinner = new();
TimeSpan pauseBetweenChecks = _pauseBetweenChecks;
Stopwatch? stopwatch = hasStopwatch ? Stopwatch.StartNew() : null;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
while (true) if (TryEnter())
{ {
cancellationToken.ThrowIfCancellationRequested(); return true;
}
if (TryEnter()) if (hasStopwatch && stopwatch!.Elapsed >= timeout)
{ {
return true; return false;
} }
if (stopwatch is not null && stopwatch.Elapsed >= timeout) if (spinner.Count < 10)
{ {
return false; spinner.SpinOnce();
} continue;
}
if (spinner.Count < 10) if (hasPause)
{ {
spinner.SpinOnce(); Thread.Sleep(pauseBetweenChecks);
continue; spinner.Reset();
} }
else
{
Thread.Yield();
}
}
}
if (_hasPause) [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
{
Thread.Sleep(_pauseBetweenChecks);
spinner.Reset();
}
else
{
Thread.Yield();
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Wait(CancellationToken cancellationToken) => Wait(Timeout.InfiniteTimeSpan, cancellationToken); 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); public bool Wait() => Wait(Timeout.InfiniteTimeSpan, CancellationToken.None);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void Release() public void Release() => _ = Interlocked.Decrement(ref _currentHolders);
{
int newValue = Interlocked.Decrement(ref _currentHolders);
if (newValue < 0)
{
Interlocked.Increment(ref _currentHolders);
throw new SynchronizationLockException("Release called more times than Wait.");
}
}
} }