我想检查Semaphore
的状态以查看是否发出信号(如果发出信号,我可以发布它)。我怎样才能做到这一点?
EDIT1:
我有两个线程,一个会等待信号量,另一个应该释放一个Semaphore
。问题是当第一个线程没有等待它时,第二个线程可能会多次调用Release()
。所以第二个线程应该检测到,如果它调用Release()
它会产生任何错误(如果你试图释放一个信号量,如果没有人等待它就会产生错误)。我怎样才能做到这一点?我知道我可以使用旗帜来做到这一点,但它很难看。有没有更好的方法?
答案 0 :(得分:12)
您可以通过调用Semaphore
并将超时值0作为参数进行检查来查看WaitOne
是否已发出信号。这将导致WaitOne
立即返回true或false值,指示信号量是否已发出信号。当然,这可能会改变信号量的状态,这使得使用起来很麻烦。
这个技巧无法帮助你的另一个原因是因为当至少有一个计数可用时,就会发信号通知信号量。听起来你想知道信号量何时可用。 Semaphore
类没有那种确切的能力。您可以使用Release
的返回值来推断计数是什么,但这会导致信号量改变其状态,当然,如果信号量在制作之前已经具有所有可用计数,它仍然会抛出异常电话。
我们需要的是具有不抛出的释放操作的信号量。这并不十分困难。如果计数可用,则下面的TryRelease
方法将返回true;如果信号量已经位于maximumCount
,则返回false。无论哪种方式,它都不会抛出异常。
public class Semaphore
{
private int count = 0;
private int limit = 0;
private object locker = new object();
public Semaphore(int initialCount, int maximumCount)
{
count = initialCount;
limit = maximumCount;
}
public void Wait()
{
lock (locker)
{
while (count == 0)
{
Monitor.Wait(locker);
}
count--;
}
}
public bool TryRelease()
{
lock (locker)
{
if (count < limit)
{
count++;
Monitor.PulseAll(locker);
return true;
}
return false;
}
}
}
答案 1 :(得分:7)
看起来你需要一个其他同步对象,因为Semaphore没有提供这样的功能来检查它是否在特定时刻发出信号。
信号量允许使用WaitOne()/Release()
方法自动触发等待信号状态的代码。
您可以查看新的.NET 4
类SemaphoreSlim,它可以公开CurrentCount属性,也许您可以利用它。
<强> CURRENTCOUNT 强>
获取允许输入的线程数 SemaphoreSlim。
编辑:由于更新了问题而更新
作为一种快速解决方案,您可以通过try / catch包裹semaphore.Release()
并处理SemaphoreFullException
,它是否按预期工作?
使用SemaphoreSlim
,您可以通过以下方式检查CurrentCount:
int maxCount = 5;
SemaphoreSlim slim = new SemaphoreSlim(5, maxCount);
if (slim.CurrentCount == maxCount)
{
// generate error
}
else
{
slim.Release();
}
答案 2 :(得分:4)
使用信令实现信号量的方法如下。能够在此之外查询状态是没有意义的,因为它不是线程安全的。
使用maxThreads
个广告位创建一个实例,最初全部可用:
var threadLimit = new Semaphore(maxThreads, maxThreads);
使用以下内容等待(阻止)备用插槽(如果maxThreads
已被占用):
threadLimit.WaitOne();
使用以下内容释放插槽:
threadLimit.Release(1);
有一个完整的例子here。
答案 3 :(得分:-3)
知道信号量中所有计数何时可用是有用的。我使用了以下逻辑/解决方案。我在这里分享是因为我没有看到任何其他解决方案。
//List to add a variable number of handles
private List<WaitHandle> waitHandles;
//Using a mutex to make sure that only one thread/process enters this section
using (new Mutex(....))
{
waitHandles = new List<WaitHandle>();
int x = [Maximum number of slots available in the semaphore];
//In this for loop we spin a thread per each slot of the semaphore
//The idea is to consume all the slots in this process
//not allowing anything else to enter the code protected by the semaphore
for (int i = 0; i < x; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(TWorker));
ManualResetEvent mre = new ManualResetEvent(false);
waitHandles.Add(mre);
t.Start(mre);
}
WaitHandle.WaitAll(waitHandles.ToArray());
[... do stuff here, all semaphore slots are blocked now ...]
//Release all slots
semaphore.Release(x);
}
private void TWorker(object sObject)
{
ManualResetEvent mre = (ManualResetEvent)sObject;
//This is an static Semaphore declared and instantiated somewhere else
semaphore.WaitOne();
mre.Set();
}