等待多个回调方法完成

时间:2015-09-01 00:31:28

标签: c# multithreading asynchronous .net-2.0

我需要调用多个异步方法并等待它们全部完成。异步方法都具有在异步处理完成时执行的回调参数。因此,我认为我需要在每个回调中放置一些信号设备,然后在继续之前等待所有信号到来。

在做了一些搜索之后,我想我可以使用一个AutoResetEvents数组,然后调用WaitHandle.WaitAll来等待它们。类似的东西:

WaitHandle[] waitHandles = new WaitHandle[] 
{
    new AutoResetEvent(false),
    new AutoResetEvent(false)
};

DoWorkA((callback) =>
{
    waitHandles[0].Set();
});

DoWorkB((callback) =>
{
    waitHandles[1].Set();
});

// wait for DoWorkA and DoWorkB to finish
WaitHandles.WaitAll(waitHandles);

// continue with the processing

我想知道这是否是一种好方法,或者是否有更好/更简单的方法。我需要.Net 2.0的解决方案,但我也有兴趣知道.Net的更高版本可以提供哪些其他解决方案。

修改 尝试此代码后,我发现它不起作用。 UI线程在WaitHandles.WaitAll(waitHandles)停止,回调永远不会运行...

在DoWork方法中,有一些代码在后台线程上以异步方式运行,然后从该后台线程尝试通过从UI线程控件上调用的BeginInvoke运行回调。但是,回调永远不会在UI线程上执行。我有什么想法我做错了吗?

编辑2: 我意识到它为什么不起作用 - 调用WaitHandles.WaitAll(waitHandles)的线程与回调试图运行的线程(UI线程)相同。因此,当然如果线程正在等待信号,则回调将永远不会在同一个线程上运行,因此永远不会调用Set()。 WaitAll(waitHandles)和Set()应该可以工作,只要它们不打算在同一个线程上运行。我想我需要修复它,以便在UI线程等待时回调在后台线程上运行。如果我的想法不正确,请告诉我。

1 个答案:

答案 0 :(得分:2)

是的,使用事件是等待多个回调完成的合理方式,对于2.0,如果您不能使用外部库,则可能是最好的。

您可以使用一个事件重写代码并计算回调完成,但它可能更复杂(同时允许无限数量的回调)。或者可以通过Semaphore实现类似的方法。

如果您使用4.5 +而不是使用async / await重写方法可能是更好的选择。

  // use "async Task(...)" as equivalent of "void DoWorkA(...)".
  async Task<int> DoWorkAAsync(int arg1)
  {
     var serviceResult = await service.CallAsync(arg1);
     return ParseServiceResult(serviceResult);
  }

  async Task<int> DoWorkBAsync() 
  { 
     ... await SomeAsync(1,2,3);...
     return someResult;
  }

  var tasks = new[] {DoWorkAAsync(42), DoWorkBAsync() }; 
  await Task.WhenAll(tasks);

  var resultOfA = tasks[0].Result;