[英]Solving race condition using SemaphoreSlim
當兩個線程同時訪問共享變量時,就會出現競爭條件。 第一個線程讀取變量,第二個線程從變量中讀取相同的值。
我在StartAsync
中使用了SemaphoreSlim
來防止競爭條件,即兩個線程可能同時更改_clientWebSocket
。 如果我們在Timer
中調用 StartAsync 可能會發生這種情況。
StopAsync
怎么樣? 如果 StopAsync 沒有包裝在 SemaphoreSlim 中,那么兩個線程通過if
條件並調用 CloseOutputAsync 兩次的機會是多少? 第一個將成功關閉 output,但第二個調用將失敗並出現 WebSocketException,因為 web 套接字已關閉。 考慮到我們沒有改變任何變量,這是否也是一種競爭條件? 考慮到我的代碼的其他部分沒有關閉 web 套接字,它是否會發生,我真的需要包裝 CloseOutputAsync 的 try/catch 嗎?
我在 StopAsync 中重用了 SemaphoreSlim 以防止同時調用 StartAsync 和 StopAsync,這是個好主意嗎?
private readonly SemaphoreSlim _semaphore = new(1, 1);
public async Task StartAsync(string url)
{
await _semaphore.WaitAsync().ConfigureAwait(false);
try
{
var ws = new ClientWebSocket();
_clientWebSocket = ws;
await _clientWebSocket.ConnectAsync(new Uri(url), CancellationToken.None).ConfigureAwait(false); // TODO: Handle
_tokenSource = new CancellationTokenSource();
_ = ReceiveLoopAsync(ws, _tokenSource.Token);
_ = SendLoopAsync(ws);
}
finally
{
_semaphore.Release();
}
}
public async Task StopAsync()
{
await _semaphore.WaitAsync().ConfigureAwait(false);
try
{
if (_clientWebSocket is { State: not (WebSocketState.Aborted or WebSocketState.Closed or WebSocketState.CloseSent) })
{
try
{
await _clientWebSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception) // thrown when we try to close an already closed socket
{
}
}
_clientWebSocket?.Dispose();
_clientWebSocket = null;
_tokenSource?.Cancel();
}
finally
{
_semaphore.Release();
}
}
我會說,如果您希望StopAsync
被並行調用,那么這些措施是值得的。
盡管我在您的代碼中看到了另一個潛在缺陷 - 您在開始和停止之間共享_clientWebSocket
和_tokenSource
,因此您可能會在下一種情況下結束:
StartAsync
並初始化_clientWebSocket
和_tokenSource
並存在信號量StartAsync
並覆蓋_clientWebSocket
和_tokenSource
StopAsync
調用StopAsync
,這將停止由Thread 2創建的ClientWebSocket
,但沒有人會關閉由Thread 1創建的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.