开发者

How to check the state of a semaphore

I want to check the state of a Semaphore to see if it is signalled or not (so if t is signalled, I can release it). How can I do this?

EDIT1:

I have two threads, one would wait on semaphore and the other should release a Semaphore. The problem is that the second thread may call Release() several times when the first thread is not waiting on it. So the second thread should detect that if it calls Release() it generate any error or not (it generate an error if you try to release a semaphore if nobody waiting on it). How can I do this?开发者_Python百科 I know that I can use a flag to do this, but it is ugly. Is there any better way?


You can check to see if a Semaphore is signaled by calling WaitOne and passing a timeout value of 0 as a parameter. This will cause WaitOne to return immediately with a true or false value indicating whether the semaphore was signaled. This, of course, could change the state of the semaphore which makes it cumbersome to use.

Another reason why this trick will not help you is because a semaphore is said to be signaled when at least one count is available. It sounds like you want to know when the semaphore has all counts available. The Semaphore class does not have that exact ability. You can use the return value from Release to infer what the count is, but that causes the semaphore to change its state and, of course, it will still throw an exception if the semaphore already had all counts available prior to making the call.

What we need is a semaphore with a release operation that does not throw. This is not terribly difficult. The TryRelease method below will return true if a count became available or false if the semaphore was already at the maximumCount. Either way it will never throw an exception.

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;
        }
    }
}


Looks like you need an other synchronization object because Semaphore does not provide such functionality to check whether it is signalled or not in specific moment of time.

Semaphore allows automatic triggering of code which awaiting for signalled state using WaitOne()/Release() methods for instance.

You can take a look at the new .NET 4 class SemaphoreSlim which exposes CurrentCount property perhaps you can leverage it.

CurrentCount
Gets the number of threads that will be allowed to enter the SemaphoreSlim.

EDIT: Updated due to updated question

As a quick solution you can wrap semaphore.Release() by try/catch and handle SemaphoreFullException , does it work as you expected?

Using SemaphoreSlim you can check CurrentCount in such way:

 int maxCount = 5;
 SemaphoreSlim slim = new SemaphoreSlim(5, maxCount);            

 if (slim.CurrentCount == maxCount)
 {
    // generate error
 }
 else
 {
   slim.Release();
 }


The way to implement semaphore using signalling is as follows. It doesn't make sense to be able to query the state outside of this, as it wouldn't be threadsafe.

Create an instance with maxThreads slots, initially all available:

var threadLimit = new Semaphore(maxThreads, maxThreads);

Use the following to wait (block) for a spare slot (in case maxThreads have already been taken):

threadLimit.WaitOne();

Use the following to release a slot:

threadLimit.Release(1);

There's a full example here.


Knowing when all counts are available in a semaphore is useful. I have used the following logic/solution. I am sharing here because I haven't seen any other solutions addressing this.

//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();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜