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