2011-02-03 83 views
2

我有類似於下面的代碼的多個塊:使用泛型委託掛鉤的異步調用

void GetPerson(Action<PersonView, Exception> callback); 

... 

IsBusy = true; 
_personRequested = true; 
_service.GetPerson((person, error) => 
{ 
if (error != null) 
    { 
    return; 
    } 
    _person = person; 
    _personLoaded = true; 
    IsBusy = false; 
}); 

的問題我運行到是給定類可能火了多個不同的異步調用,並IsBusy屬性必須是'聰明'的,因爲只要調用'A'完成,不會關閉,但'B'和'C'仍然處於待定狀態。因此_personRequested和_personLoaded布爾值。但是,我想去更通用的東西,但有點不確定如何繼續。

我最初的想法是設置一個函數,將上面的代碼作爲代理使用,但我不斷陷入奇怪的語法。我喜歡這樣的功能,我只是簡單地把所有東西都包裝起來,並把它作爲一個匿名方法傳遞給我的函數,然後在那個函數和回調函數中處理我的類的繁忙狀態。

任何幫助表示讚賞,謝謝。

回答

3

如果你正在尋找的東西是一個指示器,正在使用的東西,你最好使用計數器而不是簡單的布爾標誌。然後,您可以使用Interlocked.IncrementInterlocked.Decrement以線程安全的方式修改該值。

聲明這個類級別:

private volatile int isBusyCounter; 

Interlocked.Increment(ref isBusyCounter); 
_personRequested = true; 
_service.GetPerson((person, error) => 
{ 
if (error != null) 
    { 
    return; 
    } 
    _person = person; 
    _personLoaded = true; 
    Interlocked.Decrement(ref isBusyCounter); 
}); 

(需要使用的Interlocked因爲你修改多個線程上的價值,這確保了更新不會互相沖突;我們不關心訂單,因爲無論先發生還是發生其他情況,您都會得到相同的值)

然後,請不要只檢查IsBusy,請檢查IsBusy > 0。該變量需要爲volatile,以便後續讀取方法內的變量不會被優化(換句話說,如果您在給定函數內在循環中檢查此條件或多次檢查此條件,那麼我們將volatile放在那裏以確保每次都檢查該值,而不是在本地緩存)。

+0

這比我最初提出的要簡單得多。這應該很好。 – Brandorf 2011-02-03 19:59:49

0

每件都用計數器和增量開始和結束遞減,確保你讓比賽安全