2013-01-14 8 views
5

Mam klasy połączenia, które ma kilka async metod, takich jak SendText, SendImage itpAsynchroniczny licznik, który może być oczekiwana na

Klasa połączenie ma metodę Disconnect, a gdy to się nazywa muszę być ostrożny aby nie zmieniać stanu wewnętrznego klasy przed zakończeniem wszystkich metod asynchronicznych.

Wierzę, że dobrym sposobem, aby to osiągnąć, jest po prostu utrzymywanie sumy uruchomionych operacji, a kiedy chcę się rozłączyć, mogę po prostu ustawić Disconnecting = true, a następnie poczekać, aż liczba osiągnie 0

myślę o czymś na wzór tej

class ReferenceCounter 
{ 
    void Increment(); 

    void Decrement(); 

    async Task WaitForCounterToReachZero(); 
} 

Następnie po uruchomieniu operacji asynchronicznych mogłem zrobić

refCounter.Increment(); 

kiedy kończy

refCounter.Decrement(); 

i wewnątrz metody Disconnect

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

Czy istnieje .NET zbudowany w klasach, jak to?

A co ważniejsze dla mnie, czy jest lepszy sposób na zrobienie tego?

Jeśli był kod synchroniczny byłoby tak proste, jak

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

Właśnie się zbudowany w klasie CountdownEvent który robi to samo, ale nie ma metody asynchronicznej Wait ani nie ma żadnych wydarzeń, więc musiałbym zablokować.

Odpowiedz

4

Cóż, zakładając, że nigdy nie zwiększamy ponownie po zrobić to 0, można zrobić coś takiego:

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; } } 
} 

Następnie można oczekiwać someLatch.Task. Alternatywnie, można zrobić zatrzask sama awaitable:

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

powinieneś rozważyć, w jaki sposób chcą zabezpieczyć się przed „liczenia wzrasta po dostaniu się do 0” aspekcie thuogh - zastanów się, co chcesz chcesz to zrobić . (W powyższym kodzie, po ustawieniu wartości TCS, dalsze oczekiwanie zakończy się natychmiast.)

+0

To miła, elegancka realizacja tego, co miałem na myśli. Nie muszę się martwić, że liczba wzrasta po zejściu do 0, ponieważ boid "disconnecting" uniemożliwi dalsze operacje. Poza tym, czy uważasz, że jest to dobry sposób na radzenie sobie z takim scenariuszem? Obawiam się, że powodem, dla którego taka klasa nie istnieje w ramach, jest to, że takie rzeczy byłyby mile widziane. Czy znalazłeś się w podobnej sytuacji i zrobiłeś coś inaczej? – NoPyGod

+2

@NoPyGod: Nie jest całkiem jasne, czy naprawdę potrzebujesz liczby - mówisz o obciążeniu metod asynchronicznych ... czy wszystkie zwracają 'Zadanie' lub coś podobnego? Jeśli tak, 'Task.WhenAll' jest twoim przyjacielem. Możesz zachować pulę zaległych zadań i po prostu poczekać na 'Task.WhenAll', aby poczekać, aż wszystkie zostaną zakończone. –

+0

Mogłem to zrobić, ale wewnątrz ciała metody asynchronicznej nie mam dostępu do zadania, które ma zostać zwrócone.Aby osiągnąć to, co sugerujesz, musiałbym owinąć wewnętrzną metodę, która zwraca Zadanie, które mogę następnie dodać do puli zaległych zadań. Wydaje się to bardziej zmyślone niż sugeruję, ale jeśli jest to zalecana praktyka w takich sytuacjach, wolałbym to zrobić w ten sposób. Biorąc pod uwagę twoje oczywiste doświadczenie w tej dziedzinie, jestem bardzo zainteresowany twoją opinią. – NoPyGod

Powiązane problemy