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);
}
时间消耗功能结束了。在调试器中逐步进入它并在每行运行一行,直到结束并到达最后的'}'。这意味着它结束了,对吧?
--- [编辑答案] ---- 它通过JUST替换线
System.Threading.Thread.Sleep(0001);
与
Application.DoEvents();
我猜它会运行后台,但是没有收到答案,也没有更新IsBusy标签。
谢谢大家,很棒的答案,帮了很多忙!
答案 0 :(得分:34)
您的循环导致死锁,BGW无法完成。问题是RunWorkerCompleted事件,它是在UI线程上引发的。 BGW魔法的那一点需要UI线程空闲,它必须抽取其消息循环。问题是,UI线程不是空闲的,它不是在发送消息,而是停留在for循环中。因此,事件处理程序无法运行且IsBusy保持为真。
你需要以不同的方式做到这一点。利用RunWorkerCompleted事件运行此for循环后通常运行的代码。抵制在循环中调用Application.DoEvents()的所有诱惑。
答案 1 :(得分:3)
我建议您更改代码以处理RunWorkerCompleted
事件,以便在BackgroundWorker
完成工作时收到通知。有一个示例说明如何使用the official documentation中的BackgroundWorker
。
答案 2 :(得分:2)
我在使用后台工作程序时遇到了同样的问题,得出的结论是,如果你在循环中使用sleep(),它就会卡住。您可以使用RunWorkerCompleted事件并设置一个布尔标志来指示每个工作程序何时完成。
或者,如果您想要中止线程,无论您是否可以使用线程而不是后台工作程序。然而,您在背景工作者提供的事件方面失去了易用性。
答案 3 :(得分:1)
你的主线程需要抽取Windows消息(在你的while循环中调用Application.DoEvents,或者更好的方法是使用Systems.Windows.Forms.Timer而不是循环)。
如果您不提取Windows消息,则不会处理后台工作人员的“已完成”通知,因此状态将保持忙碌状态。
答案 4 :(得分:1)
我遇到了类似的问题,而我要解决的问题是用main try... catch... and finally...
语句包含main函数。
答案 5 :(得分:0)
.IsBusy仅表示后台工作人员正在执行操作。它会很忙,直到“某事”完成。似乎“某事”没有完成,让你的背景工作者忙碌。
因此,如果您可以解释什么是“某事”,并且可能需要多长时间在主线程上执行“某事”,这将有所帮助。
答案 6 :(得分:0)
问题是你在worker.RunWorkerAsync()
内所做的一切都没有完成。也许有一些无限循环或类似于DoWork
事件中定义的循环。
这是一个工作示例,它选择下一个自由职业者:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
private static List<MyWorker> _Workers;
static void Main(string[] args)
{
_Workers = new List<MyWorker>();
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();
}
}
}
答案 7 :(得分:-1)
以下示例给出了针对您的问题的解决方案。就像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();
}
}