C
C#2y ago
kuba_z2

❔ ❔ ❔ SemaphoreSlim that can be entered without waiting

Hello, I am trying to find way to easily control how much threads can enter semaphore. I need something like SemaphoreSlim but that supports entering without waiting or Releasing with minus values. For example:
await semaphoreSlim.WaitAsync();
try
{
if (something)
semaphoreSlim.Release(10); // allows 10 more threads to enter
else
semaphoreSlim.Release(-10); // limits 10 threads from entering
}
finally
{
semaphoreSlim.Release();
}
await semaphoreSlim.WaitAsync();
try
{
if (something)
semaphoreSlim.Release(10); // allows 10 more threads to enter
else
semaphoreSlim.Release(-10); // limits 10 threads from entering
}
finally
{
semaphoreSlim.Release();
}
I there any built in object to do it? I really don't want to implement such thing myself.
2 Replies
kuba_z2
kuba_z22y ago
Ok, I had to write it myself:
internal class AdjustableSemaphoreSlim
{
private readonly object _lock = new();
private readonly LinkedList<TaskCompletionSource> _sources = new();
private int _count;

public AdjustableSemaphoreSlim(int initialCount)
{
_count = initialCount;
}

public void Release()
{
lock (_lock)
{
_count++;
if (_sources.Count != 0)
{
_sources.First!.Value.SetResult();
_sources.RemoveFirst();
}
}
}

public void Release(int count)
{
lock (_lock)
{
_count += count;
for (int i = Math.Min(_sources.Count, count); i > 0; i--)
{
_sources.First!.Value.SetResult();
_sources.RemoveFirst();
}
}
}

public void Enter(int count)
{
lock (_lock)
_count -= count;
}

public Task WaitAsync()
{
lock (_lock)
{
if (--_count >= 0)
return Task.CompletedTask;
else
{
TaskCompletionSource source = new();
_sources.AddLast(source);
return source.Task;
}
}
}
}
internal class AdjustableSemaphoreSlim
{
private readonly object _lock = new();
private readonly LinkedList<TaskCompletionSource> _sources = new();
private int _count;

public AdjustableSemaphoreSlim(int initialCount)
{
_count = initialCount;
}

public void Release()
{
lock (_lock)
{
_count++;
if (_sources.Count != 0)
{
_sources.First!.Value.SetResult();
_sources.RemoveFirst();
}
}
}

public void Release(int count)
{
lock (_lock)
{
_count += count;
for (int i = Math.Min(_sources.Count, count); i > 0; i--)
{
_sources.First!.Value.SetResult();
_sources.RemoveFirst();
}
}
}

public void Enter(int count)
{
lock (_lock)
_count -= count;
}

public Task WaitAsync()
{
lock (_lock)
{
if (--_count >= 0)
return Task.CompletedTask;
else
{
TaskCompletionSource source = new();
_sources.AddLast(source);
return source.Task;
}
}
}
}
Accord
Accord2y ago
Looks like nothing has happened here. I will mark this as stale and this post will be archived until there is new activity. Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity. Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.