Есть ли разница между AutoResetEvent и Семафором с maxCount = 1?
Я читаю следующую статью:
http://www.albahari.com/threading
и я не могу понять разницу между AutoResetEvent и семафором, инициализированным maxCount = 1. Просто чтобы убедиться, что я правильно понял... есть ли разница в этих двух конструкциях, учитывая, что использование?
Спасибо!
Ответы
Ответ 1
Да, конечно, есть разница. A Semaphore
используется для дросселирования доступа к ресурсу или блоку кода. Когда WaitOne
называется потоком, он блокируется до тех пор, пока не будет доступен счет из семафора. Чтобы сделать доступный счет, вы должны вызвать Release
. Семафор с максимальным числом 1 часто называют двоичным семафором. Семафор такого рода позволяет только доступ к ресурсу или блочному коду из одного потока. Вы можете использовать двоичный семафор вместо мьютекса или монитора. Важно помнить о Semaphore
, что его состояние управляется вручную с помощью вызовов WaitOne
и Release
.
An AutoResetEvent
, с другой стороны, в основном используется как механизм сигнализации. Один поток будет блокироваться посредством вызова WaitOne
, ожидающего сигнала. Другой поток вызовет Set
, чтобы инициировать этот сигнал. ARE публикует этот сигнал для одного и только одного потока, а затем немедленно сбрасывает ARE в состояние unsignaled. Важно помнить о AutoResetEvent
в том, что он вручную сигнализируется посредством вызова Set
и автоматически reset после того, как возвращается один вызов WaitOne
.
Итак, вот резюме различий:
- Состояние
Semaphore
контролируется вручную.
- Состояние
AutoResetEvent
установлено вручную, но автоматически reset.
- При потоках
Semaphore
обычно балансируются вызовы Release
и WaitOne
.
- При
AutoResetEvent
один поток обычно обозначается как сигнализатор, а другой - официант.
- A
Semaphore
дросселирует доступ к ресурсу или блоку кода.
- A
AutoResetEvent
сигнализирует поток, чтобы принять какое-то действие.
Подумайте о AutoResetEvent
как о двери в коридор. Дверь позволит получить один и только один человек через дверь после получения команды для этого. Как только человек проходит через дверь, он немедленно закрывается и ждет другую команду. Пока дверь продолжает получать новые команды, коридор может заполнять столько людей, сколько количество заданных команд.
Подумайте о Semaphore
как о двери в тот же коридор. Дверь позволит нескольким людям в коридоре. Дверь остается открытой, пока коридор не достигнет предела заполняемости, и в это время дверь закрывается. После того, как кто-то выходит из коридора через другую сторону, эта дверь снова открывается.
Update:
Вот простейший возможный пример, демонстрирующий, что что-то явно отличается.
static void Main()
{
var are = new AutoResetEvent(false);
are.Set();
are.Set();
var semaphore = new Semaphore(0, 1);
semaphore.Release();
semaphore.Release();
}
Неудивительно, что вы получите исключение во втором вызове semaphore.Release
, тогда как второй вызов Set
проходит через штраф. Причина в том, что ARE устанавливает булевский флаг, тогда как семафор пытается увеличить счет.
Методы WaitOne
будут работать одинаково, но методы Release
и Set
не будут. Именно по этой причине двоичный семафор не является взаимозаменяемым с ARE. Однако в некоторых случаях ARE может быть взаимозаменяемым с двоичным семафором.
Один сценарий, где есть перекрытие, - в случае защелки для одного потока.
public static void Main()
{
var latch = new AutoResetEvent(false);
new Thread(
() =>
{
latch.WaitOne(); // Wait for the latch.
}).Start();
latch.Set(); // Release the latch.
}
Вот сценарий, который может быть удовлетворен только AutoResetEvent
.
static void Main()
{
var are = new AutoResetEvent(false);
new Thread(
() =>
{
while (true)
{
are.WaitOne();
Console.WriteLine("go");
Thread.Sleep(2000);
}
}).Start();
while (true)
{
are.Set();
Console.WriteLine("pulse");
Thread.Sleep(1000);
}
}
Ответ 2
An AutoResetEvent
, чтобы использовать метафоры Джо Альбахари:
похож на турникет с билетами: вставка билета позволяет ровно одному человеку через
так что это как односторонняя дверь.
Напротив, a Semaphore
со счетом одного похоже на комнату, которая может удерживать только одного человека и имеет знак "Занятый". Семафоры предназначены для контроля доступа к ресурсам (комнате), а счетчик указывает, сколько из них ресурсов (сколько людей может поместиться в комнате).
Ответ 3
В большинстве случаев то же самое с точки зрения пользователя, одно незначительное различие - это несколько последовательных сигналов на AutoResetEvent
, что будет неуместным для моделирования проблемы потребления ресурсов. Ниже вы найдете статью "Событие auto- reset - это просто глупый семафор".
http://blogs.msdn.com/b/oldnewthing/archive/2006/06/22/642849.aspx
Ответ 4
Семафор с max 1 аналогичен нормальному System.Threading.Monitor или блокировке ", если мы игнорируем тот факт, что именованные системные семафоры видны во всей операционной системе..", которые предоставляют критический раздел. Только один поток позволяет получить доступ к этому методу или рекурсии, а при завершении использовать другой поток, чтобы использовать его ", если есть ожидающий поток, который блокируется до тех пор, пока текущий поток не завершит использование ресурс". поэтому только один поток может получить доступ к ресурсу.
Вы можете думать о AutoResetEvent как уведомлении, поток будет ждать, пока не будет получено уведомление из другого потока, и другой поток позже установит, чтобы другой поток ожидал уведомления снова "note что AutoResetEvent автоматически снова установит ожидающий поток"...
Примером для AutoRestEvent является производитель/потребитель с использованием коллекции, первый поток будет ждать и элемент, который будет добавлен, чтобы потреблять его, другой поток "производитель" всякий раз, когда элемент добавляется, он сигнализирует "уведомлять" "ожидающий поток", который был заблокирован в ожидании уведомления ", первый поток будет обрабатывать" потреблять "этот новый добавленный элемент, а затем снова ждать, пока не будет добавлен другой элемент.
//Edit: Если вы уже знаете разницу между AutoResetEvent
и Semaphore
и спрашиваете "как ваш комментарий"
Если мы ограничились использованием только WaitOne и Set для ARE
Если вы используете только _autoResetEvent.WaitOne()
и _autoResetEvent.Set()
, вы можете добиться того же результата, но вы должны использовать его осторожно -, используя _semaphore.WaitOne()
и _semaphore.Release()
:
AutoResetEVent _autoResetEvent = new AutoResetEvent(true);
Semaphore _semaphore = new Semaphore(1, 1);
private void Foo()
{
_autoResetEvent.WaitOne();
try
{
//some code
Console.WriteLine("Thread At Foo Entered {0}", Thread.CurrentThread.ManagedThreadId);
}
finaly
{
_autoResetEvent.Set();
}
}
private void Bar()
{
_semaphore.WaitOne();
try
{
//some code
Console.WriteLine("Thread At Bar Entered {0}", Thread.CurrentThread.ManagedThreadId);
}
finaly
{
_semaphore.Release();
}
}
void Main()
{
new Thread(Foo) { IsBackground = true }.Start();
new Thread(Foo) { IsBackground = true }.Start();
new Thread(Bar) { IsBackground = true }.Start();
new Thread(Bar) { IsBackground = true }.Start();
Thread.Sleep(2000);//give it some time to execute.
Console.ReadLine();
}
//output is something like this:
Thread At Foo Entered 11
Thread At Foo Entered 12
Thread At Far Entered 13
Thread At Far Entered 14
Ответ 5
Семафор используется для контроля доступа к критическому разделу. Auto/ManualResetEvent используется, когда вы хотите сигнализировать другим потокам, что произошло определенное событие, чтобы они могли реагировать на них - они не имеют никакого отношения к защите входа в критическую секцию.
Я не уверен, какое конкретное использование вы ссылаетесь, но я думаю, вы могли бы использовать блокировки и события для реализации семафора, поэтому ответ на ваш вопрос, вероятно, не будет и да в зависимости от того, что вы после.