Подтвердить что ты не робот

Как проверить состояние семафора

Я хочу проверить состояние Semaphore, чтобы увидеть, сигнализировано ли оно или нет (поэтому, если t сигнализирован, я могу его освободить). Как я могу это сделать?

EDIT1:

У меня есть два потока, один будет ждать семафора, а другой должен освободить Semaphore. Проблема в том, что второй поток может вызвать Release() несколько раз, когда первый поток не ждет его. Таким образом, второй поток должен обнаружить, что если он вызывает Release(), он генерирует любую ошибку или нет (он генерирует ошибку, если вы пытаетесь выпустить семафор, если никто не ждет на нем). Как я могу это сделать? Я знаю, что могу использовать флаг для этого, но он уродлив. Есть ли лучший способ?

4b9b3361

Ответ 1

Вы можете проверить, сигнализируется ли Semaphore, вызывая WaitOne и передавая значение тайм-аута 0 в качестве параметра. Это приведет к тому, что WaitOne немедленно вернется с истинным или ложным значением, указывающим, был ли семафор сигнализирован. Это, конечно, может изменить состояние семафора, что делает его громоздким в использовании.

Другая причина, по которой этот трюк не поможет вам, заключается в том, что семафор называется сигналом, когда доступно хотя бы один счет. Похоже, вы хотите знать, когда семафор имеет все возможности. Класс Semaphore не обладает такой точной способностью. Вы можете использовать возвращаемое значение из Release, чтобы указать, что такое счет, но это заставляет семафор изменять его состояние и, конечно же, он все равно будет генерировать исключение, если семафор уже имел все подсчеты до совершения вызова.

Нам нужен семафор с операцией освобождения, которая не бросает. Это не сложно. Приведенный ниже метод TryRelease возвращает true, если счет стал доступным или false, если семафор уже находился на maximumCount. В любом случае это никогда не вызовет исключения.

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

Ответ 2

Похоже, вам нужен другой объект синхронизации, потому что Semaphore не предоставляет таких функций, чтобы проверить, сигнализируется ли оно или нет момент времени.

Семафор позволяет автоматически запускать код, ожидающий состояния сигнализации, используя, например, методы WaitOne()/Release().

Вы можете взглянуть на новый класс .NET 4 SemaphoreSlim, который предоставляет CurrentCount свойство, возможно, вы можете использовать его.

CURRENTCOUNT
Получает количество потоков, которые будут разрешены для ввода СемафорСлим.

EDIT: Обновлено из-за обновленного вопроса

В качестве быстрого решения вы можете обернуть semaphore.Release() с помощью try/catch и handle SemaphoreFullException, работает ли оно так, как вы ожидали?

Используя SemaphoreSlim, вы можете проверить CurrentCount таким образом:

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

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

Ответ 3

Способ реализации семафора с использованием сигнализации заключается в следующем. Не имеет смысла запрашивать состояние вне этого, так как оно не будет потокобезопасным.

Создайте экземпляр с maxThreads слотами, изначально доступными:

var threadLimit = new Semaphore(maxThreads, maxThreads);

Для ожидания (блока) для запасного слота используйте следующее: (если maxThreads уже выполнено):

threadLimit.WaitOne();

Для выхода слота используйте следующее:

threadLimit.Release(1);

Здесь приведен полный пример здесь.

Ответ 4

Зная, когда все счёты доступны в семафоре, полезно. Я использовал следующую логику/решение. Я здесь, потому что я не видел других решений, касающихся этого.

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