SemaphoreSlim有一個WaitAsync()方法,需要一個CancellationToken. 我希望在取消該令牌時釋放信號量,但情況似乎并非如此。考慮下面的代碼:
var tokenSource = new CancellationTokenSource();
var semaphore = new SemaphoreSlim(1, 1);
// CurrentCount is 1
await semaphore.WaitAsync(tokenSource.Token);
// CurrentCount is 0 as we'd expect
tokenSource.Cancel(); // Token is cancelled
for(var i = 0; i< 10; i )
{
var c = semaphore.CurrentCount; // Current count remains 0, even though token was cancelled
await Task.Delay(1000);
}
即使在令牌被取消后,CurrentCount仍然為 0。我猜這是設計使然,但是CancellationToken如果在取消令牌時不釋放信號量,究竟用于什么?謝謝!
uj5u.com熱心網友回復:
背景
SemaphoreSlim 類
代表 Semaphore 的輕量級替代方案,它限制可以并發訪問資源或資源池的執行緒數。
...
每次執行緒進入信號量時計數遞減,每次執行緒釋放信號量時遞增。為了進入信號量,執行緒呼叫 Wait 或 WaitAsync 多載之一。要釋放信號量,它呼叫 Release 多載之一。當計數達到零時,對 Wait 方法之一的后續呼叫將阻塞,直到其他執行緒釋放信號量。如果多個執行緒被阻塞,則沒有保證的順序(例如 FIFO 或 LIFO)來控制執行緒何時進入信號量。
SemaphoreSlim.CurrentCount
獲取可以進入 SemaphoreSlim 物件的剩余執行緒數。
...
CurrentCount 屬性的初始值是通過呼叫 SemaphoreSlim 類建構式來設定的。每次呼叫Wait 或WaitAsync 方法都會遞減,每次呼叫Release 方法都會遞增。
也就是說,每次進入一個信號量,就減少了可以進入的剩余執行緒。如果您已成功輸入,則計數遞減。
呼叫正在等待的CancellationToken只會對等待 的執行緒產生影響WaitAsync,或者如果您嘗試再次等待令牌。
為了回答這個問題,CancellationToken僅用于 awaiting WaitAsync,它不影響可以進入SemaphoreSlim.
此外
我認為真正相關的問題是,您是否需要發布SemephoreSlim已取消的一個!答案是否定的。等待SemephoreSlim并沒有成功進入或影響計數,它正在等待,因為沒有執行緒允許。
最后,您是否需要釋放SemephoreSlim因超時過載而超時的 a。答案是,這個方法回傳一個bool是否輸入成功,需要檢查回傳值來判斷是否需要釋放。
有趣的事實
這就是為什么您不將等待放入釋放 slim 的 try finally 模式中的確切原因。
// this can throw, or timeout
var result = await semaphore.WaitAsync(someTimeOut, tokenSource.Token);
if(!result)
return;
try
{
// synchronized work here
}
finally
{
semaphore.Release();
}
不恰當的釋放會導致各種各樣的問題,遲早會導致另一個例外,因為你超過了最大數量。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/360981.html
上一篇:使用GoogleAdminAPI(C#/.Net)--如何向用戶添加第一個關系?
下一篇:反序列化回傳空物件Java
