Reputation: 51
So right now I have a method that calls a different method three times.
List<BackgroundWorker> bgws = new List<BackgroundWorker>();
AutoResetEvent _workerCompleted = new AutoResetEvent(false);
void methodA () {
methodB(); //bw1
methodB(); //bw2
methodB(); //bw3
//wait for the background workers that were kicked off above to finish
_workerCompleted.WaitOne();
Console.Writeline("hey");
}
void methodB() {
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bgws.Add(bw);
bw.DoWork += (sender, DoWorkEventArgs) => { bwWork(sender, DoWorkEventArgs, info); };
bw.ProgressChanged += (sender, ProgressChangedEventArgs) => { bwProgressChanged(sender, ProgressChangedEventArgs, info); };
bw.RunWorkerCompleted += (sender, RunWorkerCompletedEventArgs) => { bwCompleted(sender, RunWorkerCompletedEventArgs, info); };
bw.RunWorkerAsync();
}
The bwWork
and bwProgressChanged
events shouldn't matter too much. The former is just processing a file, the latter is updating a progress bar and label.
private void bwCompleted(object senderr,
System.ComponentModel.RunWorkerCompletedEventArgs e, SenderInfo info)
{
BackgroundWorker bw = (BackgroundWorker)senderr;
Console.WriteLine(Path.GetFileName(info.path) + " : Finished.");
bgws.Remove(bw); //remove the bw from the list
//remove events from bw
bw.DoWork -= (sender, DoWorkEventArgs) => { bwWork(sender, DoWorkEventArgs, info); };
bw.ProgressChanged -= (sender, ProgressChangedEventArgs) => { bwProgressChanged(sender, ProgressChangedEventArgs, info); };
bw.RunWorkerCompleted -= (sender, RunWorkerCompletedEventArgs) => { bwCompleted(sender, RunWorkerCompletedEventArgs, info); };
//dispose bw
bw.Dispose();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
if (bgws.Count == 0) //if there are no more bw's, we're good to go
{
MessageBox.Show("Done.");
bgws.Clear();
_workerCompleted.Set();
}
}
So in the end, I want all of the background workers to finish what they're doing before "hey" is printed out. I tried using the AutoResetEvent and ManualResetEvent, yet nothing seemed to happen when they were present. What I mean is that none of the background workers even ran when I included them.
I would invoke a thread, but I'm a little reluctant because I was told background workers were the thing to use when doing background work and updating UI. Is there any way that I can wait on the three background workers so that I can continue on with my program?
Upvotes: 1
Views: 996
Reputation: 21
Know I'm two years late but this is what I did in a similar situation.
Created a completed counter.
Added one to the completed counter each time a BGW
from the list finished.
Had a seperate MonitorBGW
setup with a while loop kinda like what follows.
While(CompletedCounter < ListBGWs.Count){Thead.Sleep(2000)}
//Put my code I wanted run after they all completed here.
Hope this helps someone :)
Upvotes: 1
Reputation: 26917
I believe the issue is that the BackgroundWorker does DoWork
on a separate thread, but uses the thread it is created on to run ProgressChanged
and RunWorkerCompleted
events so they can update the UI. But if you already have the UI thread tied up in a WaitOne
or other spin, you can't execute those events.
In your bwCompleted
when bgws.Count == 0
why don't you call a methodA_AfterDone
to handle the read of methodA
and just have methodA
end after bw3?
Upvotes: 1
Reputation: 2561
Simple you don't use BackgroundWorker and switch to Tasks. Task.Run(() => Your work );
And after you do that you can use Task.WaitAll(task1,task2);
You can switch any EAP to Tasks. And with async you can make this with ease.
Upvotes: -1