5 ответов:
всякий раз, когда вы захотите контролировать выполнение нескольких потоков в приложении. Хотя это не только означает, что только один поток увеличивает счетчик; но пусть потоки запускаются/останавливаются или приостанавливаются после события.
посмотреть WaitHandles-Auto / ManualResetEvent и мьютекс
-- EDIT--
WaitHandleС что вы "используете" для управления выполнением потоков'. Не про ручки не доступный в потоке; его об использовании их в потоке.это может быть жирный пример, но, пожалуйста, потерпите меня; подумайте о том, что леди дает пять разных тональных свистков пяти девушкам и говорит им дуть в свисток всякий раз, когда
somethingпроизойдет; процесс для каждой девушки, чтобы дунуть в свисток, и леди будет знать, кто дунул в свисток.теперь это не о том, чтобы делиться свистками друг с другом, это о том, вероятно, для леди, чтобы использовать их для "контролировать" исполнение или процесс, как девушки будут дуть в свисток.
поэтому технически процесс будет заключаться в:
- создать событие ожидания (объект ManualResetEvent)
- Регистрация событий,
WaitHandle.WaitAny(events);- после завершения выполнения операции в потоке,
.Set(), который сказал бы WaitHandle, что " я сделал!'.например, рассмотрим пример из приведенной ссылки. Я добавил шаги для вас, чтобы понять логику. Это не жестко закодированные шаги, но просто так вы можете понять.
class Test { static void Main() { //STEP 1: Create a wait handle ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle for (int i=0; i < events.Length; i++) { events[i] = new ManualResetEvent(false); Runner r = new Runner(events[i], i); new Thread(new ThreadStart(r.Run)).Start(); } //STEP 2: Register for the events to wait for int index = WaitHandle.WaitAny(events); //wait here for any event and print following line. Console.WriteLine ("***** The winner is {0} *****", index); WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method. Console.WriteLine ("All finished!"); } } class Runner { static readonly object rngLock = new object(); static Random rng = new Random(); ManualResetEvent ev; int id; internal Runner (ManualResetEvent ev, int id) { this.ev = ev;//Wait handle associated to each object, thread in this case. this.id = id; } internal void Run() { //STEP 3: Do some work for (int i=0; i < 10; i++) { int sleepTime; // Not sure about the thread safety of Random... lock (rngLock) { sleepTime = rng.Next(2000); } Thread.Sleep(sleepTime); Console.WriteLine ("Runner {0} at stage {1}", id, i); } //STEP 4: Im done! ev.Set(); } }
WaitHandleявляется абстрактным базовым классом для двух часто используемых дескрипторов событий:AutoResetEventиManualResetEvent.оба этих класса позволяют одному потоку "сигнализировать" один или несколько других потоков. Они используются для синхронизации (или сериализации активности) между потоками. Это достигается с помощью
SetиWaitOne(илиWaitAll) методов. Например:резьбы 1:
// do setup work myWaitHandle.Set();резьба 2:
// do setup work myWaitHandle.WaitOne(); // this code will not continue until after the call to `Set` // in thread 1 completes.это простейший пример, и есть множество из них, доступных в интернете. Основная идея заключается в том, что
WaitOneиспользуется для ожидания сигнала от другого потока, который указывает, что что-то случилось. В случаеAsyncWaitHandle(который возвращается при асинхронном вызове делегата),WaitOneпозволяет заставить текущий поток ждать завершения асинхронной операции.когда
AutoResetEventилиManualResetEventне установлены, звонкиWaitOneбудет блокировать вызывающий поток, покаSetназывается. Эти два класса отличаются только тем, чтоAutoResetEvent"отменяет" событие после успешного вызоваWaitOneзавершает, делая последующие вызовы блокировать снова доSetназывается.ManualResetEventдолжно быть" unset " явно вызываяReset.
WaitAllиWaitAnyстатические методы наWaitHandleкласс, который позволяет указать массивWaitHandlesждать дальше.WaitAllбудет блокировать до все из поставляемых ручек являютсяSet, тогда какWaitAnyтолько до один из нихSet.
это абстрактный класс, вы не используете его прямо. Конкретные производные классы являются ManualResetEvent, AutoResetEvent, мьютекс и семафор. Важные классы в панели инструментов для реализации синхронизации потоков. Они наследуют методы WaitOne, WaitAll и WaitAny, вы используете их для обнаружения того, что один или несколько потоков сигнализировали условие ожидания.
типичный сценарий использования для ручного / AutoResetEvent должен сказать потоку выйти или позволить потоку сигнализировать, что он прогрессировал важный момент последовательности. Семафор позволяет ограничить количество потоков, выполняющих действие. Или реализовать синхронизацию потоков, которая не должна иметь сходства с конкретным потоком. Мьютекс существует для присвоения права собственности на раздел кода одному потоку, оператор блокировки часто применяется и там.
об этом написаны книги. Джо Даффи параллельное программирование в Windows является последним и самым большим. Настоятельно рекомендуется, если вы подумайте о написании резьбового кода.
представьте, что у вас есть массив с 1000 элементов в нем. Вам нужно сделать некоторую обработку на каждом из этих элементов. Эта работа займет некоторое время, но не связана с вводом/выводом.
например, возможно, вам нужно использовать каждый элемент для создания веб-запроса с низкой пропускной способностью. У вас есть много пропускной способности для запроса многих элементов одновременно, и задержка в каждом веб-запросе означает, что выполнение одного за раз может занять больше времени, чем вы хотите.
войдите в мир параллели программирование. Сегодня есть несколько способов справиться с этой задачей, и
WaitHandleявляется фундаментальной его частью. Даже если вы не используетеWaitHandleнепосредственно, какой бы вариант вы ни выбрали, скорее всего, опираясь наWaitHandleнапримерWaitAllилиWaitAnyза кулисами.продолжая пример, скажем, у вас есть типичный четырехъядерный процессор. В этой ситуации не имеет большого смысла иметь более 4 потоков одновременно.* так 4 потока, но 1000 элементов; что а вы знаете?
один вариант использует
WaitAny. Вы начинаете 4 нити, и каждый разWaitAnyметод возвращает вам начать другой, пока все 1000 элементов не будут поставлены в очередь. Обратите внимание, что это плохой пример дляWaitAny, потому что мы знаем, сколько элементов существует всего и может получить доступ к любому из элементов с той же скоростью.WaitAnyлучше, когда у вас есть только последовательный доступ. Есть и другие, похожие ситуации, когдаWaitAnyможет иметь много смысла.другой вариант использует
WaitAll. Вместо того, чтобы ставить в очередь по одному элементу за раз, вы настраиваете один поток для каждого из четырех ядер, назначая ему другой сегмент 250 элементов массива. С помощью этой опции, вы можете использоватьWaitAllожидание завершения процесса.
* на самом деле, это не так. Обычно существует определенное количество времени ввода-вывода, когда процессор будет простаивать, так что вы можете сделать лучше, имея более одного потока, идущего на ядро. Но это история для другого раза.
здесь есть несколько очень длинных ответов. Для тех, кто ищет короткий ответ:
Wait handle-это механизм для того, чтобы заставить один поток ждать, пока другой поток не достигнет определенной точки.
вы также можете иметь несколько потоков и/или несколько потоков, которые ждут, отсюда
WaitOne,WaitAllиWaitAnyметоды. Существует также несколько вариантов семантики, доступных при выборе одного из этих классов:Mutex,Semaphore,ManualResetEvent,AutoResetEventкоторые хорошо документированы.
Comments