2013-01-14 69 views
5

我有具有幾個異步方法如SendText,SendImage等的連接類被期待已久的異步計數器它可以在

的連接類有一個斷開的方法,並且當它被稱爲我必須小心在所有異步方法完成執行之前,不要開始更改類的內部狀態。

我相信一個很好的方法來實現這個目標是簡單地保持執行中的操作總數,然後當我想斷開連接時,我可以簡單地設置Disconnecting = true,然後等待計數達到0

我在想沿着這

class ReferenceCounter 
{ 
    void Increment(); 

    void Decrement(); 

    async Task WaitForCounterToReachZero(); 
} 

線的東西然後異步操作開始時我能做

refCounter.Increment(); 

當結束

refCounter.Decrement(); 

和Disconnect方法

disconnecting = true; 
taskCancellationSource.Cancel(); 
await refCounter.WaitForCounterToReachZero(); 
Cleanup(); 

內是否有任何內置的.NET類也是這樣嗎?

對我來說更重要的是,有沒有更好的方法來做到這一點?

如果它是同步的代碼,這將是這麼簡單

lock (thisLock) 
{ 
    while (counter > 0) 
     Monitor.Wait(thisLock); 
} 

我剛剛發現了建於CountdownEvent類做同樣的事情,但它沒有異步等待的方法也不會有任何事件,所以我不得不封鎖。

回答

4

好吧,假設你將永遠不會再增加後讓它0,你可以做這樣的事情:

public class Latch 
{ 
    private int count = 0; 
    private readonly TaskCompletionSource<object> tcs = 
     new TaskCompletionSource<object>(); 

    public void Increment() 
    { 
     Interlocked.Increment(ref count); 
    } 

    public void Decrement() 
    { 
     if (Interlocked.Decrement(ref count) == 0) 
     { 
      tcs.TrySetValue(null); 
     } 
    } 

    public Task Task { get { return tcs.Task; } } 
} 

然後你就可以等待someLatch.Task。另外,您也可以使鎖本身awaitable:

public TaskAwaiter GetAwaiter() 
{ 
    return tcs.Task.GetAwaiter(); 
} 

你或許應該考慮要如何防範「數量的增加,越來越下降到0後」方面thuogh - 想想你想要它做的事。 (在上面的代碼中,一旦TCS的值已經設置,進一步的等待將立即完成。)

+0

這是一個很好的優雅的實現我腦海中的想法。因爲_disconnecting bool將阻止進一步的操作,所以我不必擔心計數會下降到0。除此之外,你認爲這是處理這種情況的好方法嗎?我擔心的是,在框架中不存在這樣一個階級的原因是因爲這樣的事情會被壓制。你是否發現自己處於類似的狀況,並以不同的方式做事? – NoPyGod

+2

@NoPyGod:你是否真的需要一個計數並不十分清楚 - 你說的是有一堆異步方法......他們都會返回「任務」或類似的東西嗎?如果是這樣,'Task.WhenAll'是你的朋友。你可以保留一堆未完成的任務,並等待Task.WhenAll等待完成。 –

+0

我可以這樣做,但在異步方法體內,我無法訪問將要返回的任務。爲了實現你的建議,我將不得不包裝一個內部方法,該方法返回任務,然後我可以將其添加到未完成任務池中。這似乎比我所建議的更有人氣,但如果這是針對這些情況的推薦做法,那麼我寧願這樣做。鑑於您在該領域的顯而易見的專業知識,我對您的意見非常感興趣。 – NoPyGod