2013-10-20 48 views
2

TestAwaitTaskArrayAsync()可以從代碼中的多個位置調用。我需要鎖定taskArray的執行並異步等待,直到下一次調用開始執行taskArray之前完成所有任務。下面是代碼:在鎖中執行的等待任務數組

private async Task TestAwaitTaskArrayAsync() 
     { 
      Task[] taskArray; 
      lock (_lock_taskArray) 
      { 
       taskArray = new Task[] 
       { 
       Task.Run(() => 
       { 
        SomeMethod1(); 
       }), 
       Task.Run(() => 
       { 
        SomeMethod2(); 
       }) 
       }; 
      } 
      await Task.WhenAll(taskArray); 
     } 

地等待着鎖是不允許的,所以我可以在必要時使用AsyncLock,而是試圖保持簡單。這段代碼是否正確並且線程安全?我不確定是否等待Task.WhenAll(taskArray);可以在鎖之外,我應該使用AsyncLock來代替嗎?

+0

如果你的'taskArray'實際上是一個局部變量,那麼你根本不需要鎖定任何東西。 –

+0

@Stephen Cleary,taskArray是本地的,但SomeMethod1()和SomeMethod2()更改很多變量,所以當同時調用TestAwaitTaskArrayAsync()幾次時,結果可以混合。 – as74

+0

在這種情況下,您可以使用'ConcurrentExclusiveSchedulerPair'和/或TPL Dataflow網格找到更好的解決方案。 –

回答

7

您正在使用的鎖幾乎沒有效果,因爲創建任務非常快並且不會與任何內容發生衝突。在異步設置中實現互斥的方式是使用SemaphoreSlim類。它是一個支持任務異步模式的鎖。

SemaphoreSlim sem = new SemaphoreSlim(1); 
    private async Task TestAwaitTaskArrayAsync() 
    { 
     await sem.WaitAsync(); 
     try { 
     Task[] taskArray = new Task[] 
      { 
      Task.Run(() => 
      { 
       SomeMethod1(); 
      }), 
      Task.Run(() => 
      { 
       SomeMethod2(); 
      }) 
      }; 
     } 
     await Task.WhenAll(taskArray); 
     } 
     finally { sem.Release(); } 
    } 

在同步方式這本來就容易:

lock (_lock_taskArray) 
Parallel.Invoke(() => SomeMethod1(),() => SomeMethod2()); 

完成。

如果您願意,您還可以使用AsyncLock。這應該允許您使用using結構來可靠地釋放鎖。

+0

這個問題談論'AsyncLock'(儘管它不會說哪一個),這可能也會起作用。 – svick

+0

另外,'SemaphoreSlim'沒有無參數的構造函數。我想你想要'新的SemaphoreSlim(1)'。 (當然,字段不能是'var'。) – svick

+0

@svick添加到AsyncLock的鏈接。 – as74