背景工作者永远不会停止忙碌

for (do it a bunch of times) { while (backgroundWorker1.IsBusy && backgroundWorker2.IsBusy && backgroundWorker3.IsBusy && backgroundWorker4.IsBusy && backgroundWorker5.IsBusy) { System.Threading.Thread.Sleep(0001); } if (!backgroundWorker1.IsBusy) { backgroundWorker1.RunWorkerAsync(); } else if (!backgroundWorker2.IsBusy) { backgroundWorker2.RunWorkerAsync(); } else if (!backgroundWorker3.IsBusy) { backgroundWorker3.RunWorkerAsync(); } else if (!backgroundWorker4.IsBusy) { backgroundWorker4.RunWorkerAsync(); } else if (!backgroundWorker5.IsBusy) { backgroundWorker5.RunWorkerAsync(); } } 

它运行五次(每个BG工作一次)并且卡住了一会儿。 背景工作者不要再忙吗? 我该如何查询空房情况?

注意:有5个工作线程,这可以确保它们都不会停止,总是为它们分配工作。 但他们拒绝告诉我什么时候可用,我认为这将有一个简单的解决方案..

– [编辑请求] —

实际上它只是一个虚拟参数,我删除它并忘了把它拿出来,我只用它来调用dowork,谁做了脏工作:

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { timeconsumingfunction(publicstring); } 

时间消耗function结束了。 在调试器中逐步进入它并在每行运行一行,直到结束并到达最后的’}’。 这意味着它结束了吧?

— [EDIT ANSWER] —-它通过JUST替换线路起作用

 System.Threading.Thread.Sleep(0001); 

 Application.DoEvents(); 

我想它会运行后台,但没有收到答案,也没有更新IsBusy标签。

谢谢大家,很棒的答案,帮了很多忙!

您的循环导致死锁,BGW无法完成。 问题是RunWorkerCompleted事件,它是在UI线程上引发的。 那一点BGW魔术需要UI线程空闲,它必须抽取其消息循环。 问题是,UI线程没有空闲而且它没有抽取消息,它被卡在for循环中。 因此,事件处理程序无法运行且IsBusy保持为true。

你需要以不同的方式做到这一点。 利用RunWorkerCompleted事件运行此for循环后通常运行的代码。 抵制在循环中调用Application.DoEvents()的所有诱惑。

我建议您更改代码以处理RunWorkerCompleted事件,以便在BackgroundWorker完成其工作时收到通知。 有一个如何在官方文档中使用BackgroundWorker的示例。

我在使用后台工作程序时遇到了同样的问题,得出的结论是,如果你在循环中使用sleep(),那么它就会卡住。 您可以使用RunWorkerCompleted事件并设置一个布尔标志来指示每个工作程序何时完成。

或者,如果您想要中止线程,无论您是否可以使用线程而不是后台工作程序。 然而,您在后台工作人员提供的事件方面失去了易用性。

你的主线程需要抽取Windows消息(在你的while循环中调用Application.DoEvents,或者更好的方法是使用Systems.Windows.Forms.Timer而不是循环)。

如果您不提取Windows消息,则不会处理后台工作人员的“已完成”通知,因此状态将保持忙碌状态。

我遇到了类似的问题,我所做的就是用try... catch... and finally...声明来包含main函数。

.IsBusy仅表示后台工作者实际执行操作。 它会很忙,直到“某事”完成。 似乎“某些东西”没有完成,让你的背景工作者忙碌。

因此,如果您可以解释什么是“某事”,并且可能需要多长时间在主线程上执行“某事”,这将有所帮助。

问题是,无论你在worker.RunWorkerAsync()做什么都不会完成。 也许有一些无限循环或类似于你的DoWork事件中定义的东西。

这是一个工作示例,它选择下一个免费工作者:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Threading; namespace ConsoleApplication1 { class Program { private static List _Workers; static void Main(string[] args) { _Workers = new List(); for (int i = 0; i < 5; i++) { _Workers.Add(CreateDefaultWorker(i)); } StartJobs(20000); Console.ReadKey(); } private static void StartJobs(int runtime) { Random rand = new Random(); DateTime startTime = DateTime.Now; while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(runtime)) { var freeWorker = GetFreeWorker(); if (freeWorker != null) { freeWorker.Worker.RunWorkerAsync(new Action(() => DoSomething(freeWorker.Index, rand.Next(500, 2000)))); } else { Console.WriteLine("No free worker available!"); Console.WriteLine("Waiting for free one..."); WaitForFreeOne(); } } } private static MyWorker GetFreeWorker() { foreach (var worker in _Workers) { if (!worker.Worker.IsBusy) return worker; } return null; } private static void WaitForFreeOne() { while (true) { foreach (var worker in _Workers) { if (!worker.Worker.IsBusy) return; } Thread.Sleep(1); } } private static MyWorker CreateDefaultWorker(int index) { var worker = new MyWorker(index); worker.Worker.DoWork += (sender, e) => ((Action)e.Argument).Invoke(); worker.Worker.RunWorkerCompleted += (sender, e) => Console.WriteLine("Job finished in worker " + worker.Index); return worker; } static void DoSomething(int index, int timeout) { Console.WriteLine("Worker {1} starts to work for {0} ms", timeout, index); Thread.Sleep(timeout); } } public class MyWorker { public int Index { get; private set; } public BackgroundWorker Worker { get; private set; } public MyWorker(int index) { Index = index; Worker = new BackgroundWorker(); } } } 

下面的示例中给出了针对您的问题的工作解决方案。 就像Hans Passant解释的那样,你的代码在后台工作程序中运行,但每个线程的RunWorkerCompleted只在ui Thread中进行评估。 为此,您可以在线程的UI队列(ThreadPool)中排队您的请求。 这样,UI会评估RunWorkerCompletedEvent,然后跳转回代码。

 for (int i = 0; i < 999999; ++i) { System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback((x) => { while (backgroundWorker1.IsBusy && backgroundWorker2.IsBusy) { System.Threading.Thread.Sleep(0); } // Code that is beging executed after all threads have ended. myCode(); })); if (!backgroundWorker1.IsBusy) { backgroundWorker1.RunWorkerAsync(); } else if (!backgroundWorker2.IsBusy) { backgroundWorker2.RunWorkerAsync(); } }