Улучшение C # в Fire-and-Forget - PullRequest
2 голосов
/ 31 марта 2010

Привет

У меня есть программа, которая создает несколько экземпляров класса, запускает один и тот же длительный метод Update для всех экземпляров и ожидает завершения. Я придерживаюсь подхода Кева из этого вопроса о добавлении обновления в ThreadPool.QueueUserWorkItem.

В основной проге я сплю несколько минут и проверяю логическое значение в последнем дочернем элементе, чтобы увидеть, сделано ли

while(!child[child.Length-1].isFinished) {
    Thread.Sleep(...);
}

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

Спасибо

UPDATE: Там не должно быть блокировки. Каждый из этих экземпляров имеет свой URL-адрес веб-службы, который запрашивает их, и выполняет аналогичную работу с ответом. Они все делают свое дело.

Ответы [ 4 ]

1 голос
/ 31 марта 2010

Это не выглядит хорошо. Почти никогда не существует веских оснований полагать, что, когда последний поток завершен, остальные также выполняются. Если вы как-то не блокируете рабочие потоки, чего вам никогда не следует делать. Также не имеет смысла Sleep (), ожидая завершения потока. С тем же успехом вы можете выполнять работу, выполняемую этим потоком.

Если у вас запущено несколько потоков, присвойте каждому из них ManualResetEvent. По завершении вы можете ждать с WaitHandle.WaitAll (). Обратный отсчет счетчика потоков с помощью класса Interlocked также может работать. Или используйте CountdownLatch.

1 голос
/ 31 марта 2010

Блокирующий способ ожидания немного более элегантен, чем опрос. См. Monitor.Wait / Monitor.Pulse (Semaphore тоже работает нормально) для простого способа блокировки и подачи сигнала. В C # есть некоторый синтаксический сахар вокруг класса Monitor в виде ключевого слова lock.

1 голос
/ 31 марта 2010

Если вы знаете количество операций, которые будут выполнены, используйте обратный отсчет и событие:

Activity[] activities = GetActivities();
int remaining = activities.Length;
using (ManualResetEvent finishedEvent = new ManualResetEvent(false))
{
    foreach (Activity activity in activities)
    {
        ThreadPool.QueueUserWorkItem(s =>
        {
            activity.Run();
            if (Interlocked.Decrement(ref remaining) == 0)
                finishedEvent.Set();
        });
    }
    finishedEvent.WaitOne();
}

Не опрашивать о завершении. .NET Framework (и ОС Windows в целом) имеет ряд потоковых примитивов, специально предназначенных для предотвращения необходимости в спин-блокировках, а цикл опроса с Sleep на самом деле является просто медленной спин-блокировкой.

1 голос
/ 31 марта 2010

Вы можете попробовать Семафор .

...