观察以下代码:

var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnAsyncOperationCompleted;
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);

现在假设我要等到bw完成工作。正确的做法是什么?

我的解决方案是这样的:
bool finished = false;
var handler = GetTheRightHandler();
var bw = new BackgroundWorker();
bw.RunWorkerCompleted += (sender, args) =>
{
  OnAsyncOperationCompleted(sender, args);
  finished = true;
});
bw.DoWork += OnDoWorkLoadChildren;
bw.RunWorkerAsync(handler);
int timeout = N;
while (!finished && timeout > 0)
{
  Thread.Sleep(1000);
  --timeout;
}
if (!finished)
{
  throw new TimedoutException("bla bla bla");
}

但我不喜欢它。

我考虑过用同步事件替换finished标志,在RunWorkerCompleted处理程序中设置它,然后在其上阻塞,而不是执行while-sleep循环。

las,这是错误的,因为代码可能在WPF或WindowsForm同步上下文中运行,在这种情况下,我将阻塞与RunWorkerCompleted处理程序运行所在的线程相同的线程,这显然不是很明智的举动。

我想知道一个更好的解决方案。

谢谢。

编辑:

P.S.
  • 故意设计示例代码来阐明我的问题。我完全了解完成回调,但是我想知道如何等待完成。那是我的问题。
  • 我知道Thread.JoinDelegate.BeginInvokeThreadPool.QueueUserWorkItem等等。问题特别是关于BackgroundWorker

  • 编辑2:

    好的,我想如果我解释这种情况,它将容易得多。

    我有一个单元测试方法,该方法调用一些异步代码,而这些代码最终会使用BackgroundWorker,我可以将完成处理程序传递给该BackgroundWorker。所有代码都是我的,因此我可以根据需要更改实现。
    但是,我不打算替换ojit_code,因为它会自动使用正确的同步上下文,以便在UI线程上调用代码时,在同一UI线程上调用完成回调。

    无论如何,单元测试方法有可能在BW完成工作之前就结束了,这不好。因此,我希望等到BW完成后,并想知道实现此目标的最佳方法。

    它有更多的部分,但总体情况或多或少像我刚才描述的那样。

    最佳答案

    尝试使用AutoResetEvent类,如下所示:

    var doneEvent = new AutoResetEvent(false);
    var bw = new BackgroundWorker();
    
    bw.DoWork += (sender, e) =>
    {
      try
      {
        if (!e.Cancel)
        {
          // Do work
        }
      }
      finally
      {
        doneEvent.Set();
      }
    };
    
    bw.RunWorkerAsync();
    doneEvent.WaitOne();
    

    警告:不管发生什么情况,都应确保调用doneEvent.Set()。另外,您可能想为doneEvent.WaitOne()提供一个指定超时期限的参数。

    注意:该代码几乎是Fredrik Kalsethsimilar question的回答的副本。

    10-01 02:16
    查看更多