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
+16 -28
+16 -28
View File
@@ -14,27 +14,21 @@ public sealed class PollingSemaphore
private readonly bool _hasPause;
private int _currentHolders;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public PollingSemaphore(int maximumConcurrency, TimeSpan pauseBetweenChecks)
{
if (maximumConcurrency <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maximumConcurrency));
}
if (pauseBetweenChecks < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(pauseBetweenChecks));
}
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(maximumConcurrency, 0);
ArgumentOutOfRangeException.ThrowIfLessThan(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;
@@ -44,13 +38,16 @@ public sealed class PollingSemaphore
return false;
}
[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();
bool hasPause = _hasPause;
bool hasStopwatch = timeout != Timeout.InfiniteTimeSpan;
SpinWait spinner = new();
TimeSpan pauseBetweenChecks = _pauseBetweenChecks;
Stopwatch? stopwatch = hasStopwatch ? Stopwatch.StartNew() : null;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -60,7 +57,7 @@ public sealed class PollingSemaphore
return true;
}
if (stopwatch is not null && stopwatch.Elapsed >= timeout)
if (hasStopwatch && stopwatch!.Elapsed >= timeout)
{
return false;
}
@@ -71,9 +68,9 @@ public sealed class PollingSemaphore
continue;
}
if (_hasPause)
if (hasPause)
{
Thread.Sleep(_pauseBetweenChecks);
Thread.Sleep(pauseBetweenChecks);
spinner.Reset();
}
else
@@ -83,21 +80,12 @@ public sealed class PollingSemaphore
}
}
[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);
}