Я прочитал документацию по этому, и я думаю, что я понимаю. An AutoResetEvent
сбрасывается , когда код проходит черезevent.WaitOne()
, но ManualResetEvent
не делает.
Это правильно?
c#
.net
multithreading
autoresetevent
manualresetevent
Бен МакНил
источник
источник
Ответы:
Да. Это как разница между платной автостоянкой и дверью. Это
ManualResetEvent
дверь, которую необходимо закрыть (сбросить) вручную. ЭтоAutoResetEvent
платная автостоянка, позволяющая проехать одному автомобилю и автоматически закрывающаяся до того, как проехать следующий.источник
Просто представьте, что
AutoResetEvent
выполняетсяWaitOne()
иReset()
как единая атомарная операция.источник
Короткий ответ: да. Наиболее важным отличием является то, что AutoResetEvent позволит продолжить работу только одному ожидающему потоку. С другой стороны, ManualResetEvent будет продолжать разрешать потоки, даже несколько одновременно, до тех пор, пока вы не скажете остановить его (Сбросить).
источник
Threading в C # - Бесплатная электронная книга
ManualResetEvent - это вариант AutoResetEvent. Он отличается тем, что он не сбрасывается автоматически после того, как поток пропускается при вызове WaitOne, и поэтому функционирует как шлюз: вызов Set открывает шлюз, пропуская любое количество потоков, через которые WaitOne проходит через шлюз; Вызов Reset закрывает ворота, в результате чего очередь официантов накапливается до следующего открытия.
Эту функцию можно смоделировать с помощью логического поля gateOpen (объявленного с ключевым словом volatile) в сочетании с «spin-sleep» - многократно проверяя флаг, а затем в течение короткого промежутка времени.
ManualResetEvents иногда используются, чтобы сигнализировать, что конкретная операция завершена или что инициализация потока завершена и готова к выполнению работы.
источник
Я создал простые примеры, чтобы уточнить понимание
ManualResetEvent
противAutoResetEvent
.AutoResetEvent
: предположим, у вас есть 3 рабочих потока. Если какой-либо из этих потоков вызоветWaitOne()
все остальные 2 потока, он остановит выполнение и будет ожидать сигнала. Я предполагаю, что они используютWaitOne()
. Это похоже на; если я не работаю, никто не работает. В первом примере вы можете увидеть, чтоПри звонке
Set()
все потоки будут работать и ждать сигнала. Через 1 секунду я посылаю второй сигнал, и они выполняются и ждут (WaitOne()
). Представьте, что эти парни являются игроками футбольной команды, и если один из игроков скажет, что я подожду, пока менеджер не позвонит мне, а другие подождут, пока менеджер скажет им продолжить (Set()
)В этом примере вы можете ясно видеть, что при первом нажатии
Set()
он пропустит все потоки, а затем через 1 секунду он подает сигнал всем потокам на ожидание! Как только вы установите их снова, независимо от того, что они звонятWaitOne()
внутри, они продолжат работать, потому что вам нужно вручную позвонить,Reset()
чтобы остановить их все.Это больше касается отношений Рефери / Игроки там, независимо от того, кто из игроков получил травму, и ожидание, когда другие играют, продолжит работать. Если рефери говорит wait (
Reset()
), то все игроки будут ждать следующего сигнала.источник
autoResetEvent.WaitOne()
похоже на
как атомная операция
источник
Хорошо, обычно не рекомендуется добавлять 2 ответа в одну и ту же ветку, но я не хотел редактировать / удалять свой предыдущий ответ, поскольку это может помочь другим способом.
Теперь я создал гораздо более понятный и понятный фрагмент приложения для запуска на уроке ниже.
Просто запустите примеры на двух разных консолях и наблюдайте за их поведением. Там вы получите гораздо более четкое представление о том, что происходит за кулисами.
Событие ручного сброса
Событие с автосбросом
источник
AutoResetEvent поддерживает логическую переменную в памяти. Если логическая переменная имеет значение false, то она блокирует поток, а если логическая переменная имеет значение true, разблокирует поток.
Когда мы создаем экземпляр объекта AutoResetEvent, мы передаем значение по умолчанию логического значения в конструкторе. Ниже приведен синтаксис создания экземпляра объекта AutoResetEvent.
Метод WaitOne
Этот метод блокирует текущий поток и ожидает сигнала от другого потока. Метод WaitOne переводит текущий поток в состояние потока Sleep. Метод WaitOne возвращает true, если он получает сигнал, иначе возвращает false.
Вторая перегрузка метода WaitOne ожидает указанное количество секунд. Если он не получает сигнал, поток продолжает свою работу.
Мы вызвали метод WaitOne, передав 2 секунды в качестве аргументов. В цикле while он ожидает сигнала в течение 2 секунд, затем продолжает работу. Когда поток получил сигнал, WaitOne возвращает значение true, выходит из цикла и выдает «Поток получил сигнал».
Установить метод
Метод AutoResetEvent Set отправил сигнал ожидающему потоку для продолжения его работы. Ниже приведен синтаксис вызова метода Set.
ManualResetEvent поддерживает логическую переменную в памяти. Когда логическая переменная имеет значение false, она блокирует все потоки, а когда логическая переменная имеет значение true, она разблокирует все потоки.
Когда мы создаем экземпляр ManualResetEvent, мы инициализируем его с логическим значением по умолчанию.
В приведенном выше коде мы инициализируем ManualResetEvent со значением false, что означает, что все потоки, которые вызывают метод WaitOne, будут блокироваться, пока какой-то поток не вызовет метод Set ().
Если мы инициализируем ManualResetEvent со значением true, все потоки, которые вызывают метод WaitOne, не будут блокироваться и будут свободны для продолжения.
Метод WaitOne
Этот метод блокирует текущий поток и ожидает сигнала от другого потока. Он возвращает истину, если получает сигнал, иначе возвращает ложь.
Ниже приведен синтаксис вызова метода WaitOne.
Во второй перегрузке метода WaitOne мы можем указать интервал времени, в течение которого текущий поток будет ожидать сигнала. Если в течение внутреннего времени он не получает сигнал, он возвращает false и переходит на следующую строку метода.
Ниже приведен синтаксис вызова метода WaitOne с интервалом времени.
Мы должны указать 5 секунд в метод WaitOne. Если объект manualResetEvent не получает сигнал в течение 5 секунд, он устанавливает для переменной isSignalled значение false.
Задать метод
Этот метод используется для отправки сигнала всем ожидающим потокам. Метод Set () устанавливает для логической переменной объекта ManualResetEvent значение true. Все ожидающие потоки разблокированы и продолжаются.
Ниже приведен синтаксис вызова метода Set ().
Метод сброса
Когда мы вызываем метод Set () для объекта ManualResetEvent, его логическое значение остается истинным. Для сброса значения мы можем использовать метод Reset (). Метод сброса изменяет логическое значение на false.
Ниже приведен синтаксис вызова метода Reset.
Мы должны немедленно вызвать метод Reset после вызова метода Set, если мы хотим отправить сигнал потокам несколько раз.
источник
Да. Это абсолютно правильно.
Вы могли видеть ManualResetEvent как способ указать состояние. Что-то включено (установлено) или выключено (сброс). Случай с некоторой продолжительностью. Любой поток, ожидающий этого состояния, может продолжаться.
AutoResetEvent более сопоставим с сигналом. Один выстрел показывает, что что-то произошло. Событие без какой-либо продолжительности. Как правило, но не обязательно, «что-то», которое произошло, является небольшим и должно обрабатываться одним потоком - следовательно, автоматический сброс после того, как один поток использовал событие.
источник
Да все верно.
Вы можете получить представление об использовании этих двух.
Если вам нужно сказать, что вы закончили с какой-то работой и другие (потоки), ожидающие этого, теперь могут продолжить, вы должны использовать ManualResetEvent.
Если вам нужен взаимоисключающий доступ к любому ресурсу, вы должны использовать AutoResetEvent.
источник
Если вы хотите понять AutoResetEvent и ManualResetEvent, вам нужно понимать не многопоточность, а прерывания!
.NET хочет вызвать низкоуровневое программирование как можно дальше.
Прерывания - это то, что используется в низкоуровневом программировании, что соответствует сигналу, который с низкого уровня стал высоким (или наоборот). Когда это происходит, программа прерывает нормальное выполнение и перемещает указатель выполнения на функцию, которая обрабатывает это событие .
Первое, что нужно сделать, когда происходит прерывание, это сбросить его состояние, потому что оборудование работает следующим образом:
В этом разница между ManualResetEvent и AutoResetEvent.
Если произойдет событие ManualResetEvent, и я не сброслю его, в следующий раз, когда это произойдет, я не смогу его прослушать.
источник