如何检查信号量的状态

时间:2011-09-07 08:22:57

标签: c# .net multithreading semaphore

我想检查Semaphore的状态以查看是否发出信号(如果发出信号,我可以发布它)。我怎样才能做到这一点?

EDIT1:

我有两个线程,一个会等待信号量,另一个应该释放一个Semaphore。问题是当第一个线程没有等待它时,第二个线程可能会多次调用Release()。所以第二个线程应该检测到,如果它调用Release()它会产生任何错误(如果你试图释放一个信号量,如果没有人等待它就会产生错误)。我怎样才能做到这一点?我知道我可以使用旗帜来做到这一点,但它很难看。有没有更好的方法?

4 个答案:

答案 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 4SemaphoreSlim,它可以公开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();
}