PoolingSemaphore optimized.
This commit is contained in:
1 parent
60ccb3db74
commit
8f0cc17d90
1 file changed
+16
-28
@@ -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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user