Модель приложений .NET. Потоки.
Уведомление с помощью мониторов
Поток, овладевший замком монитора Monitor (Монитор), может, не покидая блока синхронизации, ожидать сигнал от другого потока, который выполняет операцию синхронизации на том же самом объекте. Поток вызывает метод Monitor::Wait (Монитор::Ожидать) и освобождает замок. Потом, когда он получит уведомление от другого потока, то повторно овладевает замком в целях синхронизации.
Поток, овладевший замком монитора Monitor (Монитор), может послать уведомление другому потоку, ожидающему разрешения на доступ к тому же самому объекту с помощью методов Pulse (Импульс, Сигнал) или PulseAll. Важно, что во время посылки сигнала поток переходит в состояние ожидания. В противном случае, если сигнал будет послан, но поток не подождет некоторое время, то другой поток будет ждать вечно и никогда не сможет получить уведомление. Такое поведение не похоже на событие возврата в исходное состояние, обсуждаемое позже в этой главе. Если много потоков ожидают сигнал, метод Pulse (Импульс, Сигнал) поместит только один поток в очередь готовых для выполнения. PulseAll поместит их все в эту очередь.
Поток, пославший импульс, больше не владеет замком монитора Monitor (Монитор), но и не блокируется; он может продолжать выполнение. Так как он больше не заблокирован, но не владеет замком, то, чтобы избежать взаимоблокировки (дедлока) или состояния гонок, этот поток должен пробовать повторно овладеть замком (с помощью методов Monitor::Enter (Монитор::Войти) или Wait (Ожидать)), перед выполнением любых потенциально опасных действий.
Пример PulseAll иллюстрирует применение методов Pulse (Импульс, Сигнал) и PulseAll. Пример во время выполнения генерирует следующую выдачу:
First thread: 2 started. Thread: 5 started. Thread: 5 waiting. Thread: 6 started. Thread: 6 waiting. Thread 5 sleeping. Done. Thread 5 awake. Thread: 5 exited. Thread 6 sleeping. Thread 6 awake. Thread: 6 exited.
Перевод такой:
Первый поток: 2 стартовал. Поток: 5 стартовал. Поток: 5 в состоянии ожидания. Поток: 6 стартовал. Поток: 6 в состоянии ожидания. Поток 5 бездействует. Сделано. Поток 5 активный. Поток: 5 вышел. Поток 6 бездействует. Поток 6 активный. Поток: 6 вышел.
Класс X содержит поле "о" типа Object (Объект), которое будет использоваться в качестве синхронизирующего замка.
Класс также содержит метод Test (Испытание), который используется в качестве делегата потока. Метод овладевает синхронизирующим замком, а затем ждет уведомления. Когда он получит уведомление, то бездействует в течение половины секунды, а затем вновь освобождает замок.
Метод main (главный) создает два потока, которые используют метод X::Test (Х::Испытание) в качестве делегата своего потока и совместно используют тот же самый объект, предназначенный для синхронизации. Затем он бездействует в течение 2 секунд, чтобы позволить потокам произвести запросы ожидания и освободить замки. Потом метод main (главный) вызывает метод PulseAll, чтобы уведомить оба ожидающих потока и освободить замки. В конечном счете, каждый поток повторно овладевает замком, выводит сообщение на консоль, и в последний раз освобождает замок.