我需要使用我自己的信号量类作为基础,用C#编写自己的FIFO/强信号量。我找到了this example,但是由于我不应该使用Monitor.Enter/Exit,所以不太正确。
这些是我的常规信号量的方法,我想知道是否有一种简单的方法可以将其调整为FIFO。
public virtual void Acquire()
{
lock (this)
{
while (uintTokens == 0)
{
Monitor.Wait(this);
}
uintTokens--;
}
}
public virtual void Release(uint tokens = 1)
{
lock (this)
{
uintTokens += tokens;
Monitor.PulseAll(this);
}
}
最佳答案
因此,SemaphoreSlim
为我们提供了一个良好的起点,因此,我们将从将其中一个包装在新类中,然后将除wait方法之外的所有内容定向到该信号量开始。
为了获得类似行为的队列,我们需要一个队列对象,并确保它在面对多线程访问时是安全的,我们将使用ConcurrentQueue
。
在此队列中,我们将放置TaskCompletionSource
对象。当我们要开始等待时,可以创建一个TCS,将其添加到队列中,然后通知信号量从队列中异步弹出下一项,并在等待结束时将其标记为“完成”。我们会知道,由于队列中有项目,因此继续的次数总是相等或更少。
然后,我们仅等待来自TCS的Task
。
我们也可以通过仅返回而不是等待它,来简单地创建一个返回任务的WaitAsync
方法。
public class SemaphoreQueue
{
private SemaphoreSlim semaphore;
private ConcurrentQueue<TaskCompletionSource<bool>> queue =
new ConcurrentQueue<TaskCompletionSource<bool>>();
public SemaphoreQueue(int initialCount)
{
semaphore = new SemaphoreSlim(initialCount);
}
public SemaphoreQueue(int initialCount, int maxCount)
{
semaphore = new SemaphoreSlim(initialCount, maxCount);
}
public void Wait()
{
WaitAsync().Wait();
}
public Task WaitAsync()
{
var tcs = new TaskCompletionSource<bool>();
queue.Enqueue(tcs);
semaphore.WaitAsync().ContinueWith(t =>
{
TaskCompletionSource<bool> popped;
if (queue.TryDequeue(out popped))
popped.SetResult(true);
});
return tcs.Task;
}
public void Release()
{
semaphore.Release();
}
}
关于c# - 如何创建FIFO/强信号量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23415708/