Как дождаться завершения BackgroundWorker, чтобы запустить другой BackgroundWorker (С#)?

Прежде всего, я все еще новичок, поэтому я был бы признателен, если бы вы проявили немного терпения :)

Я сегодня так сильно ломал голову по этому поводу.

Дело в том, что я хочу запустить три разных фоновых рабочих. Но я хотел бы подождать, пока один не закончит, чтобы запустить следующий и так далее.

Каждому фоновому работнику требуется время для завершения. Короче говоря, дело в том, что я использую WaitOne(), поэтому всякий раз, когда предыдущий фоновый рабочий говорит мне, что это сделано, я могу запустить новый, но поток пользовательского интерфейса зависает, пока три фоновых рабочих не закончат работу.

Я настраиваю другой AutoResetEvent, который позаботится обо всем, что ждет и работает.

Вот код:

AutoResetEvent _resetRIEvent = new AutoResetEvent(false);
AutoResetEvent _resetHEvent = new AutoResetEvent(false);
AutoResetEvent _resetSEvent = new AutoResetEvent(false);

await Task.Run(() => bgwTestResInd.RunWorkerAsync());
_resetRIEvent.WaitOne();

await Task.Run(() => bgwTestHipot.RunWorkerAsync());
_resetHEvent.WaitOne();

await Task.Run(() => bgwTestSurge.RunWorkerAsync());
_resetSEvent.WaitOne();

MessageBox.Show("Im done for real.");

Кроме того, разрешено ли это делать?

private void bgwTestResInd_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    _resetRIEvent.Set();
}


private void bgwTestHipot_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    _resetHEvent.Set();
}


private void bgwTestSurge_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    _resetSEvent.Set();
}

person dgls61    schedule 17.01.2017    source источник
comment
Почему вы вообще используете BGW, если можете использовать задачи?   -  person Servy    schedule 18.01.2017
comment
Я вообще начинающий программист. Я действительно не знаю, какой путь был лучше.   -  person dgls61    schedule 18.01.2017


Ответы (2)


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

await Task.Run(() => TheWorkThatTheFirstBGWWasDoing());
await Task.Run(() => TheWorkThatTheSecondBGWWasDoing());
await Task.Run(() => TheWorkThatTheThirdBGWWasDoing());

Или, если все операции связаны с процессором, вы можете просто использовать один вызов Task.Run:

await Task.Run(() =>
{
    TheWorkThatTheFirstBGWWasDoing());
    TheWorkThatTheSecondBGWWasDoing());
    TheWorkThatTheThirdBGWWasDoing());
});

Сделанный.

Если вы действительно должны использовать фоновый рабочий процесс (для чего нет веских причин, но в любом случае), то все, что вам нужно сделать, это вызвать RunWorkerAsync в завершенном обработчике BGW, который должен дождаться или, что еще лучше, просто иметь один BGW, который выполняет работу, которую выполняет первый, затем выполняет работу, которую должен выполнять второй, а затем выполняет работу, которую должен выполнять третий.

person Servy    schedule 17.01.2017
comment
Спасибо Серви. Я все еще новичок, поэтому у меня все еще есть определенные проблемы с выбором способа делать некоторые вещи. - person dgls61; 18.01.2017

Если вы все еще хотите придерживаться своего плана, вот код

class Program
{

    static void Main(string[] args)
    {

        var test=new Test();
        test.Run();
        Console.ReadKey();
    }

    private class Test
    {
        AutoResetEvent _resetRIEvent = new AutoResetEvent(false);
        AutoResetEvent _resetHEvent = new AutoResetEvent(false);
        AutoResetEvent _resetSEvent = new AutoResetEvent(false);

        private BackgroundWorker bgwTestResInd = new BackgroundWorker();
        private BackgroundWorker bgwTestHipot=new BackgroundWorker();
        private BackgroundWorker bgwTestSurge=new BackgroundWorker();
        public async void Run()
        {
            bgwTestResInd.DoWork += BgwTestResInd_DoWork;
            bgwTestHipot.DoWork += BgwTestHipot_DoWork;
            bgwTestSurge.DoWork += BgwTestSurge_DoWork;

            await Task.Run(() => bgwTestResInd.RunWorkerAsync());
            _resetRIEvent.WaitOne();


            await Task.Run(() => bgwTestHipot.RunWorkerAsync());
            _resetHEvent.WaitOne();

            await Task.Run(() => bgwTestSurge.RunWorkerAsync());
            _resetSEvent.WaitOne();

            Console.Write("Done");
        }

        private void BgwTestHipot_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("BgwTestHipot done..");
            _resetHEvent.Set();
        }

        private void BgwTestSurge_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("BgwTestSurge done..");
            _resetSEvent.Set();
        }

        private void BgwTestResInd_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("BgwTestResInd done..");
            _resetRIEvent.Set();
        }
    }
}

Просто добавьте свой код в методы DoWork, и они будут выполняться в той последовательности, в которой вы сбрасываете свои AutoResetEvents.

person Gurpreet    schedule 17.01.2017
comment
Это не устраняет проблему, которую ставит вопрос, заключающуюся в блокировке пользовательского интерфейса. - person Servy; 18.01.2017