Лучшая практика для определения, когда группа потоков сделана - PullRequest
0 голосов
/ 16 марта 2009

Как лучше всего определять, когда обрабатывается целая группа потоков? У меня есть процесс, который будет запрашивать [долго работающий] веб-сервис для произвольного числа объектов, а затем должен предпринять транзакционное действие, когда все они будут успешно завершены. В настоящее время я запускаю их асинхронно, используя делегатов из пула потоков .Net. Запуск их синхронно, побеждает цель запуска их в нескольких потоках ... Как еще я могу определить, когда ВСЕ завершены? Я, хотя и использовал coounter (иначе называемый счетчиком COM), увеличивая его для достижения потока, который запускается и уменьшая его в функции обратного вызова, и сохраняя динамический список со ссылкой на каждый поток в нем, чтобы явно отслеживать каждый из них. как они завершают, но оба эти решения кажутся немного грязными ...

Спасибо всем ... Исходя из ваших предложений и необходимости передать экземпляр объекта в асинхронный поток (представлен ниже переменной ref uPL), я использую следующий код ... ПРИМЕЧАНИЕ: IEEDAL.GetUsagePayloadReadings (uPL1) - вызов удаленной веб-службы

    foreach (MeterChannel chgChan in chgChs)
        foreach (UsagePayload uPL in chgChan.IntervalPayloads)
        {
            ManualResetEvent txEvnt = new ManualResetEvent(false);
            UsagePayload uPL1 = uPL;
            ThreadPool.QueueUserWorkItem(
                delegate(object state)
                    {
                        if (!uPL1.HasData)
                            IEEDAL.GetUsagePayloadReadings(uPL1);
                        UsageCache.PersistPayload(uPL1);
                        SavePayLoadToProcessFolder(uPL1);
                        txEvnt.Set();
                    } );
            waitHndls.Add(txEvnt);
        }
    WaitHandle.WaitAll(waitHndls.ToArray());

Ответы [ 5 ]

3 голосов
/ 16 марта 2009

Лучший способ, который я видел, это использовать защелку обратного отсчета. В выпуске MSDN Magazine за май 2007 года есть очень хорошее описание , включая источник C #

3 голосов
/ 16 марта 2009

Вы можете использовать WaitHandle.WaitAll .

2 голосов
/ 16 марта 2009

Я не знаю, является ли это «лучшей практикой» или нет, но классы System.Threading.ManualResetEvent и System.Threading.WaitHandle - это два класса, которые я считаю необходимыми, когда потоки должны сигнализировать друг другу. Вот простой пример их использования с потоками ThreadPool.

    List<WaitHandle> handles = new List<WaitHandle>();
    for ( int iii = 0; iii < 10; iii++ ) {
        ManualResetEvent transactionEvent = new ManualResetEvent( false );
        ThreadPool.QueueUserWorkItem( delegate( object state ) {
            // Do your work here...
            transactionEvent.Set();
        } );
        handles.Add( transactionEvent );
    }
    WaitHandle.WaitAll( handles.ToArray() );
2 голосов
/ 16 марта 2009

Есть несколько вариантов.

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

Другая потенциальная альтернатива - иметь ResetEvent для каждого потока. Просто установите событие в «конец» потока и проверьте его в своем основном потоке. Это может быть сложнее, однако.

1 голос
/ 16 марта 2009
Dim WaitAllEvents(1) As AutoResetEvent

Dim thread1 As Thread
Dim thread2 As Thread

thread1 = New Thread(AddressOf Thread1Worker)
thread2 = New Thread(AddressOf Thread2Worker)

WaitAllEvents(0) = New AutoResetEvent(False)
WaitAllEvents(1) = New AutoResetEvent(False)

thread1.Start()
thread2.Start()

'Main thread will wait until all instances of AutoResetEvent 
'have become signaled with a call to Set()

WaitHandle.WaitAll(WaitAllEvents)

Console.WriteLine("All threads done exiting main thread")
thread2 = Nothing
thread1 = Nothing

'...
'...

Private Sub Thread1Worker()
    Thread.Sleep(5000)
    Console.WriteLine("Thread1 done")
    WaitAllEvents(0).Set() 
End Sub

Private Sub Thread2Worker()
    Thread.Sleep(3000)
    Console.WriteLine("Thread2 done")
    WaitAllEvents(1).Set() 
End Sub
...