【问题标题】:This BackgroundWorker is currently busy and cannot run multiple tasks concurrently此 BackgroundWorker 当前很忙,无法同时运行多个任务
【发布时间】:2009-02-25 22:12:11
【问题描述】:

如果我单击启动后台工作程序两次的按钮,我会收到此错误。

This BackgroundWorker is currently busy and cannot run multiple tasks concurrently

我怎样才能避免这种情况?

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    简单:不要启动 BackgroundWorker 两次。

    您可以使用IsBusy 属性检查它是否已经在运行,因此只需更改此代码:

    worker.RunWorkerAsync();
    

    到这里:

    if( !worker.IsBusy )
        worker.RunWorkerAsync();
    else
        MessageBox.Show("Can't run the worker twice!");
    

    更新:

    如果您确实需要同时启动多个后台任务,您可以简单地创建多个 BackgroundWorker 对象

    【讨论】:

    • 在某种程度上我同意答案并不完全有用。考虑到您确实需要运行两个后台进程的情况,出现“无法运行工作程序两次”的错误并不是很好。我会假设关于为每个任务运行新的 backgroundWorkers 的答案 - 或者以某种方式排队作业是一个更好的解决方案,这不会导致您必须检查系统的其他部分是否已经启动了后台作业并采取行动在那之后。
    • IsBusy 究竟什么时候被清除?我原以为它会在RunWorkerCompleted 事件被触发之前被清除,但情况似乎并非如此(至少根据我的实验)。
    • 我认为 OP 的问题从未得到解答。尽管我认为我确实解决了部分问题。我在我的中使用了一个 TcpListener,并且在没有挂起的情况下接受连接。所以我正在寻找一些方法来打断那个电话。 OP 可能需要提供更多关于他正在使用 BackgroundWorker 做什么的信息,以确定是什么阻碍了他。
    • @omJohn8372 - 如果您在后台工作人员中使用 TcpListeners 时遇到问题,我对您的建议是不要这样做。使用 TcpListener 上的 async 方法,以便异步运行并释放主线程来做其他事情。大多数异步方法都采用 CancellationToken,如果您愿意,您可以随时使用它来关闭它们
    • @OrionEdwards 我很欣赏这个建议,这是一个很好的建议。我无法正确地回忆起我做了什么来修复它,但我确实修复了它,而不仅仅是丢弃旧对象并重新开始。我没有在 TcpListener 上使用 Async 方法的全部内容,我认为我应该 - 我以前偶然发现它们,它们似乎是处理事情的简洁方式。
    【解决方案2】:

    为您要执行的每个操作创建一个新的 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);
    }
    

    【讨论】:

    • 这是一个很好的答案。如果需要,我们如何杀死所有的 backgroundWorker?
    • @VladSpreys 我不能在评论中真正讨论线程取消,但是这个网站上有一些关于这个主题的非常好的帖子。
    • @fatcat1111 谢谢。如果我们保留对它的引用,我理解取消线程的想法。但是对于这段代码 sn-p 我们没有。
    • @VladSpreys 如果您想要一个对工作人员的引用列表,那么在 for 循环之外声明一个 List,并在循环中,在实例化工作人员后,将其添加到列表中。然后,如果您需要取消它们,请遍历列表并以最适合您的方案的任何方式取消它们。
    【解决方案3】:

    我会考虑将需要完成的任务排队。您将获得以下优势;

    • 您不必处理后台任务因其他已在运行而无法启动的问题
    • 您不必担心会用完太多线程,只需为每个任务创建一个新的后台即可。
    • 最后,队列可以让您确保后台任务的运行顺序与创建/请求的顺序相同。

    这是一个示例实现:http://thevalerios.net/matt/2008/05/a-queued-backgroundworker。我不确定是否在线程安全中实现,一旦我在我正在使用的实现中弄清楚我当前的锁定问题,我将更新我的答案。

    【讨论】:

    • 示例实现的链接已损坏
    • 这个答案是正确的,但使用代码实现而不是链接会更好
    【解决方案4】:

    尽管 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 部分加一个锁来避免。

    【讨论】:

    • 请不要这样命名你的变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多