我怎么知道多个后台工作人员何时完成?
How do I know when multiple background workers are finished?
所以现在我有一个调用不同方法三次的方法。
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();
}
bwWork
和 bwProgressChanged
事件应该无关紧要。前者只是处理一个文件,后者是更新一个进度条和标签。
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();
}
}
所以最后,我希望所有后台工作人员在 "hey" 打印出来之前完成他们正在做的事情。我尝试使用 AutoResetEvent 和 ManualResetEvent,但当它们存在时似乎什么也没有发生。我的意思是 none 的后台工作人员甚至 运行 当我包括他们时。
我会调用一个线程,但我有点不情愿,因为有人告诉我后台工作人员是在进行后台工作和更新时使用的东西 UI。有什么办法可以让我等待三个后台工作人员,以便我可以继续我的程序吗?
我认为问题在于 BackgroundWorker 在单独的线程上执行 DoWork
,但将其创建的线程用于 运行 ProgressChanged
和 RunWorkerCompleted
事件这样他们就可以更新 UI。但是,如果您已经将 UI 线程捆绑在 WaitOne
或其他自旋中,则无法执行这些事件。
在您的 bwCompleted
中,当 bgws.Count == 0
时,您为什么不调用 methodA_AfterDone
来处理 methodA
的读取,然后让 methodA
结束bw3?
很简单,您不使用 BackgroundWorker 并切换到 Tasks。 Task.Run(() => Your work );
然后你可以使用 Task.WaitAll(task1,task2);
你可以切换任何 EAP to Tasks。使用异步,您可以轻松做到这一点。
知道我迟到了两年,但这是我在类似情况下所做的。
创建了一个完整的计数器。
每当列表中的 BGW
完成时,就向已完成的计数器添加一个。
有一个单独的 MonitorBGW
设置,带有 while 循环,如下所示。
While(CompletedCounter < ListBGWs.Count){Thead.Sleep(2000)}
//Put my code I wanted run after they all completed here.
希望这对某人有所帮助:)
所以现在我有一个调用不同方法三次的方法。
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();
}
bwWork
和 bwProgressChanged
事件应该无关紧要。前者只是处理一个文件,后者是更新一个进度条和标签。
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();
}
}
所以最后,我希望所有后台工作人员在 "hey" 打印出来之前完成他们正在做的事情。我尝试使用 AutoResetEvent 和 ManualResetEvent,但当它们存在时似乎什么也没有发生。我的意思是 none 的后台工作人员甚至 运行 当我包括他们时。
我会调用一个线程,但我有点不情愿,因为有人告诉我后台工作人员是在进行后台工作和更新时使用的东西 UI。有什么办法可以让我等待三个后台工作人员,以便我可以继续我的程序吗?
我认为问题在于 BackgroundWorker 在单独的线程上执行 DoWork
,但将其创建的线程用于 运行 ProgressChanged
和 RunWorkerCompleted
事件这样他们就可以更新 UI。但是,如果您已经将 UI 线程捆绑在 WaitOne
或其他自旋中,则无法执行这些事件。
在您的 bwCompleted
中,当 bgws.Count == 0
时,您为什么不调用 methodA_AfterDone
来处理 methodA
的读取,然后让 methodA
结束bw3?
很简单,您不使用 BackgroundWorker 并切换到 Tasks。 Task.Run(() => Your work );
然后你可以使用 Task.WaitAll(task1,task2);
你可以切换任何 EAP to Tasks。使用异步,您可以轻松做到这一点。
知道我迟到了两年,但这是我在类似情况下所做的。
创建了一个完整的计数器。
每当列表中的 BGW
完成时,就向已完成的计数器添加一个。
有一个单独的 MonitorBGW
设置,带有 while 循环,如下所示。
While(CompletedCounter < ListBGWs.Count){Thead.Sleep(2000)}
//Put my code I wanted run after they all completed here.
希望这对某人有所帮助:)