2009-06-24 120 views
3

我遇到了多種編程語言中的這個問題,我只是想知道處理它的最佳方法是什麼。進行多個異步調用並在完成時執行某些操作

我有三個方法調用異步觸發。每個人都有一個回調。只有當所有三個回調都完成後,我纔想做點什麼。

什麼是最好的方式來編碼?我通常會得到所有這些公共bool標誌,並且隨着您添加更多的調用,代碼變得更加複雜。

回答

3

來自C#,我可能會使用WaitHandle.WaitAll。您可以創建一個ManualResetEvent對象的數組(每個任務要完成一個),並將該數組傳遞給WaitAll。線程化任務將分別獲得一個ManualResetEvent對象,並在準備就緒時調用Set方法。 WaitAll將阻止調用線程,直到完成所有任務。我給一個C#代碼示例:

private void SpawnWorkers() 
{ 
    ManualResetEvent[] resetEvents = new[] { 
      new ManualResetEvent(false), 
      new ManualResetEvent(false) 
     }; 

    // spawn the workers from a separate thread, so that 
    // the WaitAll call does not block the main thread 
    ThreadPool.QueueUserWorkItem((state) => 
    { 
     ThreadPool.QueueUserWorkItem(Worker1, resetEvents[0]); 
     ThreadPool.QueueUserWorkItem(Worker2, resetEvents[1]); 
     WaitHandle.WaitAll(resetEvents); 
     this.BeginInvoke(new Action(AllTasksAreDone)); 

    }); 
} 
private void AllTasksAreDone() 
{ 
    // OK, all are done, act accordingly 
} 

private void Worker1(object state) 
{ 
    // do work, and then signal the waiting thread 
    ((ManualResetEvent) state).Set(); 
} 

private void Worker2(object state) 
{ 
    // do work, and then signal the waiting thread 
    ((ManualResetEvent)state).Set(); 
} 

注意,AllTasksAreDone方法將執行對用於產卵的工人線程池線程,而不是在主線程上......我認爲很多其他語言有相似的結構。

+0

我們在什麼環境中當調用這個.BeginInvoke?這是什麼'? – 2010-08-03 23:03:52

1

如果你真的只需要等待所有完成:

  1. 創建揮發性反
  2. 同步訪問計數器上開始
  3. 增加計數器
  4. 減少對回調解僱
  5. 等待計數器達到0
0

期貨非常易於使用。期貨看起來像正常的功能,只是它們執行異步。

的類:

public struct FutureResult<T> 
{ 
    public T Value; 
    public Exception Error; 
} 
public class Future<T> 
{ 
    public delegate R FutureDelegate<R>(); 
    public Future(FutureDelegate<T> del) 
    { 
     _del = del; 
     _result = del.BeginInvoke(null, null); 
    } 
    private FutureDelegate<T> _del; 
    private IAsyncResult _result; 
    private T _persistedValue; 
    private bool _hasValue = false; 
    private T Value 
    { 
     get 
     { 
      if (!_hasValue) 
      { 
       if (!_result.IsCompleted) 
        _result.AsyncWaitHandle.WaitOne(); 
       _persistedValue = _del.EndInvoke(_result); 
       _hasValue = true; 
      } 
      return _persistedValue; 
     } 
    } 
    public static implicit operator T(Future<T> f) 
    { 
     return f.Value; 
    } 
} 

這裏我用期貨來模擬一個僵局:


     void SimulateDeadlock() 
     { 
      Future> deadlockFuture1 = new Future>(() => 
      { 
       try 
       { 
        new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString) 
         .SimulateDeadlock1(new DateTime(2000, 1, 1, 0, 0, 2)); 
        return new FutureResult { Value = true }; 
       } 
       catch (Exception ex) 
       { 
        return new FutureResult { Value = false, Error = ex }; 
       } 
      }); 
      Future> deadlockFuture2 = new Future>(() => 
      { 
       try 
       { 
        new SystemData(ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString) 
         .SimulateDeadlock2(new DateTime(2000, 1, 1, 0, 0, 2)); 
        return new FutureResult { Value = true }; 
       } 
       catch (Exception ex) 
       { 
        return new FutureResult { Value = false, Error = ex }; 
       } 
      }); 
      FutureResult result1 = deadlockFuture1; 
      FutureResult result2 = deadlockFuture2; 
      if (result1.Error != null) 
      { 
       if (result1.Error is SqlException && ((SqlException)result1.Error).Number == 1205) 
        Console.WriteLine("Deadlock!"); 
       else 
        Console.WriteLine(result1.Error.ToString()); 
      } 
      else if (result2.Error != null) 
      { 
       if (result2.Error is SqlException && ((SqlException)result2.Error).Number == 1205) 
        Console.WriteLine("Deadlock!"); 
       else 
        Console.WriteLine(result2.Error.ToString()); 
      } 
     } 

+0

這個例子中缺少一些類 – mcintyre321 2009-08-06 09:10:07

相關問題