事件調度中的競爭條件
C# 中的事件通常使用以下程式碼進行調度:
public event EventHandler SomeEvent;
...
{
....
if(SomeEvent!=null)SomeEvent();
}
登入後複製
然而,在多執行緒環境中,這種方法可能會導致競爭條件。下面是它的發生方式:
- 執行緒 1 檢查 SomeEvent 是否不為 null。
- 執行緒 2 從 SomeEvent 移除唯一已註冊的委託。
- 執行緒 1 繼續執行呼叫 SomeEvent,由於呼叫清單為空而導致異常。
解決此問題並發問題,最佳實踐是在檢查null 之前將呼叫清單複製到臨時變數:
protected virtual void OnSomeEvent(EventArgs args)
{
EventHandler ev = SomeEvent;
if (ev != null) ev(this, args);
}
登入後複製
這種方法是執行緒安全的,因為:
- Delegate.Combine和Delegate.Remove 傳回新的委託實例而不是修改現有的委託實例。
- .NET 中物件參考的賦值是原子。
- 事件存取器(新增/刪除)是同步的。
透過複製調用列表,我們確保事件處理程序被調用,即使它們在複製後被刪除已採取。但是,需要注意的是,此解決方案並不能解決已失效事件處理程序的潛在狀態問題。
以上是在 C# 中分派事件時如何避免競爭條件?的詳細內容。更多資訊請關注PHP中文網其他相關文章!