【发布时间】:2009-02-25 22:12:11
【问题描述】:
如果我单击启动后台工作程序两次的按钮,我会收到此错误。
This BackgroundWorker is currently busy and cannot run multiple tasks concurrently
我怎样才能避免这种情况?
【问题讨论】:
标签: c# backgroundworker
如果我单击启动后台工作程序两次的按钮,我会收到此错误。
This BackgroundWorker is currently busy and cannot run multiple tasks concurrently
我怎样才能避免这种情况?
【问题讨论】:
标签: c# backgroundworker
简单:不要启动 BackgroundWorker 两次。
您可以使用IsBusy 属性检查它是否已经在运行,因此只需更改此代码:
worker.RunWorkerAsync();
到这里:
if( !worker.IsBusy )
worker.RunWorkerAsync();
else
MessageBox.Show("Can't run the worker twice!");
更新:
如果您确实需要同时启动多个后台任务,您可以简单地创建多个 BackgroundWorker 对象
【讨论】:
IsBusy 究竟什么时候被清除?我原以为它会在RunWorkerCompleted 事件被触发之前被清除,但情况似乎并非如此(至少根据我的实验)。
为您要执行的每个操作创建一个新的 BackgroundWorker 对象。即,而不是:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
for (int i; i < max; i++) {
worker.RunWorkerAsync(i);
}
试试这个:
for (int i; i < max; i++) {
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(i);
}
【讨论】:
我会考虑将需要完成的任务排队。您将获得以下优势;
这是一个示例实现:http://thevalerios.net/matt/2008/05/a-queued-backgroundworker。我不确定是否在线程安全中实现,一旦我在我正在使用的实现中弄清楚我当前的锁定问题,我将更新我的答案。
【讨论】:
尽管 OP 最初要求的情况并非如此,但如果您在某种生产者-消费者中使用后台工作人员,这也可能由于竞争条件(现在发生在我身上,并寻找答案)而发生图案。
例子:
if (BckgrndWrkr == null)
{
BckgrndWrkr = new BackgroundWorker();
BckgrndWrkr.DoWork += DoWorkMethod;
BckgrndWrkr.RunWorkerAsync();
}
else if (!BckgrndWrkr.IsBusy)
{
BckgrndWrkr.RunWorkerAsync();
}
在这种情况下,存在竞争条件:第一个实例实例化一个新的后台工作程序,第二个实例到达else if 并启动后台工作程序,在第一个实例到达if 块的 RunWorkerAsync 之前,当它完成时抛出错误。
这可以通过给整个 if + if else 部分加一个锁来避免。
【讨论】: