Вы можете проверить, сигнализируется ли Semaphore
, вызвав WaitOne
и передав значение тайм-аута 0 в качестве параметра.Это приведет к немедленному возвращению WaitOne
со значением true или false, указывающим, был ли семафор сигнализирован.Это, конечно, может изменить состояние семафора, что делает его громоздким в использовании.
Еще одна причина, по которой этот трюк вам не поможет, заключается в том, что семафор считается сигнальным, когда хотя бы один счетчик доступен,Похоже, вы хотите знать, когда у семафора есть все доступные отсчеты.Класс 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;
}
}
}