Ожидание завершения любого из этих BackgroundWorker - PullRequest
3 голосов
/ 02 февраля 2010

Существует последовательность для FORM (некоторый пользовательский интерфейс), который необходимо загрузить с помощью сервиса. В настоящее время эта загрузка находится в теме BackgroundWorker. Теперь, поскольку производительность низкая ... Мы решили разделить ФОРМЫ на 2 и начать параллельную загрузку, используя другой BackgroundWorker поверх существующего потока.

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

Я пытался с AutoResetEvent. но я не смог этого достичь.

Любая помощь приветствуется.

Ответы [ 5 ]

2 голосов
/ 14 февраля 2010

Я не думаю, что сценарий действительно состоит в том, что один BackgroundWorker должен ждать другого. Что вы действительно хотите, так это запускать какое-то событие пользовательского интерфейса после (и только после) завершения обоих из них. Это тонкое, но важное различие; вторая версия намного проще для кодирования.

public class Form1 : Form
{
    private object download1Result;
    private object download2Result;

    private void BeginDownload()
    {
        // Next two lines are only necessary if this is called multiple times
        download1Result = null;
        download2Result = null;

        bwDownload1.RunWorkerAsync();
        bwDownload2.RunWorkerAsync();
    }

    private void bwDownload1_RunWorkerCompleted(object sender,
        RunWorkerCompletedEventArgs e)
    {
        download1Result = e.Result;
        if (download2Result != null)
            DisplayResults();
    }

    private void bwDownload2_RunWorkerCompleted(object sender,
        RunWorkerCompletedEventArgs e)
    {
        download2Result = e.Result;
        if (download1Result != null)
            DisplayResults();
    }

    private void DisplayResults()
    {
        // Do something with download1Result and download2Result
    }
}

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

Это действительно все, что вам нужно; Событие RunWorkerCompleted выполняется в потоке переднего плана, поэтому вам не нужно беспокоиться о синхронизации или условиях гонки. Нет необходимости в операторах lock, AutoResetEvent и т. Д. Просто используйте две переменные-члены для хранения результатов или два логических флага, если результатом любого из них может быть null.

1 голос
/ 08 февраля 2010

Джеффри Рихтер - гуру, когда дело доходит до многопоточности, и он написал удивительную библиотеку под названием Power Threading Library , которая позволяет выполнять такие задачи, как асинхронная загрузка n файлов и продолжение после их завершения (или одного или некоторые), действительно просто.

Уделите немного времени просмотру видео, узнайте об этом, и вы не пожалеете об этом. Использование библиотеки Power Threading (которая free и также имеет версию Silverlight и Compact Framework) также облегчает чтение вашего кода, что является большим преимуществом при выполнении любых асинхронных операций.

Удачи, Mark

1 голос
/ 02 февраля 2010

Вы должны иметь возможность использовать две функции AutoResetEvent и функцию WaitAll , чтобы дождаться завершения обоих. Вызовите функцию Set для объектов AutoResetEvent в соответствующем событии OnRunWorkerCompleted .

0 голосов
/ 14 февраля 2010

Просто используйте 2 объекта BackgroundWorker, и каждый из них предупреждает пользовательский интерфейс, когда он завершает работу. Таким образом, вы можете отобразить счетчик, индикатор выполнения, что угодно в пользовательском интерфейсе и обновлять его, когда результаты загрузки возвращаются из потоков. Вы также избежите риска взаимоблокировки потоков и т. Д.

Кстати, чтобы нам было все ясно, вы НИКОГДА не должны вызывать блокирующую функцию, такую ​​как WaitAll, из потока пользовательского интерфейса. Это приведет к полной блокировке пользовательского интерфейса, что заставит вас задуматься о том, что WTF происходит:)

0 голосов
/ 14 февраля 2010
int completedCount = 0;

void threadProc1() { //your thread1 proc
//do something
....

completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}

void threadProc2() { //your thread1 proc
//do something
....

completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
...