为什么BackgroundWorker总是很忙?

Dar*_*Zon 9 c# wpf dispatcher backgroundworker dispatch

我在WPF应用程序中的后台工作者中意识到了一些奇怪的东西.

我现在想要完成的是等到BW完成另一个线程.

检查以下代码:

if (bw.IsBusy)
{
    bw.CancelAsync();

    System.Threading.ThreadStart WaitThread = 
        new System.Threading.ThreadStart(delegate() {
            while (bw.IsBusy)
            {
                System.Threading.Thread.Sleep(100);
            }

            bw.RunWorkerAsync();
        });

    System.Windows.Application.Current.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Normal,
        WaitThread);  // if I remove this line, bw fires RunWorkerAsyncEvent
}
else
{
    bw.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我添加了一个Dispatcher.Invoke,等到bw不忙,但如果我调用它并且从不触发RunWorkerAsyncCompleted事件,则所有时间都很忙.虽然,如果我删除该行,FIRES事件,这真的很奇怪.

我怎么能等到bw结束?

Han*_*ant 25

这称为"死锁",这是一个非常常见的线程问题.在运行RunWorkerCompleted事件之前,BGW无法停止忙碌.该事件在您的应用程序的主线程上运行,它只能在您的主线程不忙于执行其他操作时运行.它必须是空闲的,在调度程序循环内运行.

但是你的主线程没有空闲,它被卡在while()循环内等待IsBusy返回false.所以事件永远不会运行,因为主线程忙于等待BGW完成,BGW无法完成,因为主线程永远不会空闲."致命的拥抱",又名死锁.

你必须以不同的方式做到这一点,你不能等待.比如创建另一个BGW实例.或者只是在RWC事件触发之前不允许此代码运行.或者通过设置一个标志,由RunWorkerCompleted事件处理程序测试,然后可以再次启动BGW.

  • 另一个肮脏的解决方案:如果等待循环在 MainThread 中:调用“Application.DoEvents();” 在循环。这也将解决死锁。 (2认同)

Gnu*_*utt 6

死锁的发生是由于应用程序的“主”线程无法运行(并处理事件),因此后台工作程序永远无法触发其完成的功能。您可以做的就是添加一个 Application.DoEvents(); 来允许应用程序触发此事件。

这就是我目前在类似场景中使用的方法,它看起来很有魅力!

    while (bw.IsBusy)
    {
        Application.DoEvents();
        System.Threading.Thread.Sleep(100);
    }
Run Code Online (Sandbox Code Playgroud)