當兩個執行緒同時訪問一個共享變數時,就會出現競爭條件。第一個執行緒讀取變數,第二個執行緒從變數中讀取相同的值。
我用來防止競爭條件,即兩個執行緒可能SemaphoreSlim同時更改。如果我們在.StartAsync_clientWebSocketTimer
怎么樣StopAsync?如果 StopAsync 沒有包裝在 SemaphoreSlim 中,那么兩個執行緒通過if條件并呼叫 CloseOutputAsync 兩次的機會是多少?第一個將成功關閉輸出,但第二個呼叫將因 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();
}
}
uj5u.com熱心網友回復:
我想說,如果您希望StopAsync被并行呼叫,那么值得采取這些措施。
盡管我在您的代碼中看到了另一個潛在的缺陷-您正在共享_clientWebSocket以及_tokenSource在開始和停止之間進行共享,因此您可能會在下一種情況下結束:
- 執行緒1呼叫
StartAsync并初始化_clientWebSocket并_tokenSource存在信號量 - 執行緒 2呼叫
StartAsync并覆寫_clientWebSocket和_tokenSource - 執行緒 1
StopAsync呼叫StopAsync將停止ClientWebSocket由執行緒 2創建,但沒有人會關閉由執行緒 1創建的呼叫
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/467281.html
