Какова основная концепция WaitHandle?


какова основная концепция WaitHandle в потоке C# .net? Что является использование? Когда его использовать? Какая польза от WaitAll и WaitAny методы внутри него?

5   51   2010-03-29 17:10:47

5 ответов:

всякий раз, когда вы захотите контролировать выполнение нескольких потоков в приложении. Хотя это не только означает, что только один поток увеличивает счетчик; но пусть потоки запускаются/останавливаются или приостанавливаются после события.

посмотреть WaitHandles-Auto / ManualResetEvent и мьютекс

-- EDIT--

WaitHandleС что вы "используете" для управления выполнением потоков'. Не про ручки не доступный в потоке; его об использовании их в потоке.

это может быть жирный пример, но, пожалуйста, потерпите меня; подумайте о том, что леди дает пять разных тональных свистков пяти девушкам и говорит им дуть в свисток всякий раз, когда something произойдет; процесс для каждой девушки, чтобы дунуть в свисток, и леди будет знать, кто дунул в свисток.

теперь это не о том, чтобы делиться свистками друг с другом, это о том, вероятно, для леди, чтобы использовать их для "контролировать" исполнение или процесс, как девушки будут дуть в свисток.

поэтому технически процесс будет заключаться в:

  1. создать событие ожидания (объект ManualResetEvent)
  2. Регистрация событий, WaitHandle.WaitAny(events);
  3. после завершения выполнения операции в потоке,.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 которые хорошо документированы.