简体   繁体   中英

C# backgroundworker RunworkerCompleted vs async await

Updated with answers: The true way of wait until a number of different tasks to be finished would need async await instead of background worker.

#

I know there are numerous discussion about backgroundworker but I've being searched around and cannot find the answer.

Here is my code example(basic logic, the actual code is much longer), I wonder if there is a way to get around this:

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

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

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 reasons, the MCIATS1_RunWorkerCompleted won't be triggered until the loop finished. And apparently the WaitOne is holding the loop.
Here is my question,

why RunWorkerCompleted won't be trigger the RunWorkerCompleted when the worker is actually finished the work?

Thank you.

###UPDATED SOLUTION

This is the right way of doing it.

 private async void WhateverFunction() { await Task.WhenAll(MCIATS1WorkerDoWorkAsync(param),...other tasks); } private Task MCIATS1WorkerDoWorkAsync(bkgWorkParameter param) { return Task.Run(() => { //Do whatever }); } 

It happens because when you use a BackgroundWorker it's RunWorkerCompleted event is posted to the SynchronizationContext of the thread that called RunWorkerAsync .

Because you call RunWorkerAsync on the UI thread the event can't 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 by your _MCIATS1WorkerResetEvent.WaitOne(); call.

So what it boils down to is _MCIATS1WorkerResetEvent.Set(); is waiting for MCIATS1_RunWorkerCompleted to fire to stop blocking and MCIATS1_RunWorkerCompleted is waiting for _MCIATS1WorkerResetEvent.Set(); to stop blocking the UI thread so it's message to be processed.

Both things are waiting for the other to complete before itself completes and you have a classic deadlock.

There is no need for a for loop for this problem to happen, this same problem would happen with or without out the loop, in fact the loop never gets to run it's 2nd itteration because it will have deadlocked on the first time through so it does not matter that there is a loop at all.

Depend on what kind of work your MCIATS1Worker_DoWork method do, you can consider to use async-await approach, which makes code a little bid more 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");
     }       
}

Message box will be shown 10 times every 1 second. await keyword will continue loop only after MCIATS1WorkerDoWorkAsync method has successfully finished.

With async-await your form will remain responsive and if DoWork method do some IO operations, then you will not start another thread (as BackgroundWorker do) and whole execution will happens on one thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM