Какова основная концепция WaitHandle? - программирование
Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

См. WaitHandles - Auto/ManualResetEvent и Mutex

- 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();
    }
}

Ответ 2

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 позволяет вам заставить текущий поток ждать, пока операция async не будет завершена.

Если AutoResetEvent или ManualResetEvent не установлены, вызовы WaitOne будут блокировать вызывающий поток до тех пор, пока не будет вызван вызов Set. Эти два класса отличаются только тем, что AutoResetEvent "unsets" событие, как только успешный вызов WaitOne завершается, и последующие вызовы блокируются до тех пор, пока не будет вызван Set. ManualResetEvent должен быть явно отключен, вызывая Reset.

WaitAll и WaitAny являются статическими методами класса WaitHandle, которые позволяют указать массив WaitHandles для ожидания. WaitAll будет блокироваться до тех пор, пока все предоставленные дескрипторы не будут Set, тогда как WaitAny будет блокироваться только до тех пор, пока один из них не получит Set.

Ответ 3

Это абстрактный класс, вы не используете его напрямую. Конкретными производными классами являются ManualResetEvent, AutoResetEvent, Mutex и Семафор. Важные классы в вашем инструменте для реализации синхронизации потоков. Они наследуют методы WaitOne, WaitAll и WaitAny, вы используете их для обнаружения того, что один или несколько потоков сигнализировали о состоянии ожидания.

Типичным сценарием использования для Manual/AutoResetEvent является указание потоку выйти или передать сигнал потока, который он перешел в важную точку последовательности. Семафор помогает вам ограничить количество потоков, выполняющих действие. Или реализовать синхронизацию потоков, которая не должна иметь сродства к конкретному потоку. Mutex позволяет назначать право собственности на часть кода на один поток, там также часто применяется оператор блокировки.

Об этом написаны книги. Joe Duffy Параллельное программирование в Windows является самым последним и самым большим. Настоятельно рекомендуется, если вы планируете писать код с резьбой.

Ответ 4

Идея методов WaitAll и WaitAny заключается в том, что они полезны, когда у вас много задач, которые вы хотите запускать параллельно.

Например, скажем, вы должны выполнить задание, требующее выполнения некоторой обработки для 1000 элементов в массиве, которые необходимо обрабатывать параллельно. Типичный Core 2 Duo + hyperthreading имеет только 4 логических процессора, и поэтому не имеет большого смысла иметь более 4 потоков, идущих сразу (фактически, это так, но это история в другое время - мы будем притворяться и использовать простую модель "один поток на процессор" ). Таким образом, 4 потока, но 1000 предметов; чем ты занимаешься?

Один из вариантов - использовать метод WaitAny. Вы запускаете 4 потока, и каждый раз, когда метод WaitAny возвращает вас, вы начинаете с другого, пока все 1000 элементов не будут поставлены в очередь. Обратите внимание, что это плохой пример для WaitAny, поскольку вы также можете просто разделить свой массив на 250 блоков элементов. Надеюсь, однако, это дает вам представление о ситуации, в которой WaitAny полезен. Существуют и другие аналогичные ситуации, когда WaitAny может иметь большой смысл.

Но теперь вернемся к сценарию с 4 потоками, каждый из которых обрабатывает 250 элементов из вашего массива 1000 единиц. С помощью этой опции вы можете использовать метод WaitAll, чтобы дождаться завершения всей обработки.

Ответ 5

Здесь есть очень длинные ответы. Для тех, кто ищет короткий ответ:

Wait handle - механизм для создания одного потока, пока другой поток не достигнет определенной точки.

Вы также можете ожидать несколько потоков и/или несколько потоков, ожидающих, следовательно, методы WaitOne, WaitAll и WaitAny. Существует также несколько вариантов выбора семантики, выбрав один из этих классов: Mutex, Semaphore, ManualResetEvent, AutoResetEvent, которые хорошо документированы.