C # backgroundworker RunworkerCompleted vs async waits

Updated with answers: A true way to wait until several different tasks have completed would require an asynchronous wait instead of a work background.

#

I know there are a lot of discussions about background but I am searched and cannot find an answer.

Here is my sample code (main logic, actual code is much longer), I wonder if there is a way around this:

 BackgroundWorker MCIATS1Worker = new BackgroundWorker();
    private AutoResetEvent _MCIATS1WorkerResetEvent = new AutoResetEvent(false);

    public MainWindow()
    {
        InitializeComponent();

        MCIATS1Worker = new BackgroundWorker();
        MCIATS1Worker.DoWork += new DoWorkEventHandler(MCIATS1Worker_DoWork);
        MCIATS1Worker.WorkerReportsProgress = true;
        MCIATS1Worker.WorkerSupportsCancellation = true;
        MCIATS1Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(MCIATS1_RunWorkerCompleted);

        for (int i = 1; i <= 10; i++)
        {
            //some code
            MCIATS1Worker.RunWorkerAsync();
            _MCIATS1WorkerResetEvent.WaitOne();
        }

    }

      

DoWork and runworkercompleted

void MCIATS1Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //do something here
    }

    void MCIATS1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("hello world");
        _MCIATS1WorkerResetEvent.Set();
    }

      

For some reason MCIATS1_RunWorkerCompleted will not run until the cycle is complete. And apparently WaitOne is holding the loop.
Here is my question,

why won't RunWorkerCompleted start RunWorkerCompleted when the worker actually exits?

Thank.

### UPDATED SOLUTION

This is the correct way to do it.

private async void WhateverFunction()
   {
    await Task.WhenAll(MCIATS1WorkerDoWorkAsync(param),...other tasks);
    }


private Task MCIATS1WorkerDoWorkAsync(bkgWorkParameter param)
    {
        return Task.Run(() =>
        {
            //Do whatever
        });
    }

      

+3


source to share


2 answers


Depending on what work your method MCIATS1Worker_DoWork

is doing, you may want to take an approach async-await

that makes the code a little cleaner.

private async Task MCIATS1WorkerDoWorkAsync()
{        
    await Task.Delay(1000) // do something asynchronously for 1 second
}

private async void MainWindow_Load(object sender, EventArgs e)
{
     for (int i = 1; i <= 10; i++)
     {
        //some code
        await MCIATS1WorkerDoWorkAsync();
        MessageBox.Show("hello world");
     }       
}

      



The message box will be displayed 10 times every 1 second. await

the keyword will continue to loop only after the method has successfully completed MCIATS1WorkerDoWorkAsync

.

With this, async-await

your form will remain responsive, and if the method DoWork

is doing some I / O, then you will not start another thread (like the BackgroundWorker does), and all the execution will be done in one thread.

+1


source


This is because when you use BackgroundWorker

, the event is RunWorkerCompleted

dispatched to the SynchronizationContext

thread called RunWorkerAsync

.

Because you are calling RunWorkerAsync

on the UI thread, the event cannot run until the UI thread starts processing new messages in the message loop. However, you prevented the UI thread from returning to the message loop with your call _MCIATS1WorkerResetEvent.WaitOne();

.

So what does this make it _MCIATS1WorkerResetEvent.Set();

wait to MCIATS1_RunWorkerCompleted

fire to stop the lock, and MCIATS1_RunWorkerCompleted

wait _MCIATS1WorkerResetEvent.Set();

to stop the blocking of the UI thread for it to be processed.



Both things are waiting for someone to complete their completion and you have a classic dead end.

There is no need for a loop for

for this problem, the same problem will happen with or without a loop, in fact the loop never starts its 2nd iteration because it will block at the first time, so it doesn't matter if there is a loop at all.

+3


source







All Articles