簡體   English   中英

C#訂閱所​​有對象的相同事件處理程序是否安全

[英]C# Is it thread safe to subscribe Same event handler for all Objects

我的項目中有一個情況,我連接到多個服務器並監聽事件。 每當從服務器收到事件時,Handler都應將事件添加到公共隊列進行處理。 所有連接都應將收到的事件添加到隊列中。

foreach(var item in collection)
{
        Connection c = new connection(item);

         c.start();
         c.EventReceived+=new EventHandler(myHandler);
         list.add(c);
}

protected void  myHandler(eventArgs)
{
     //add it to the concurrent queue
}

在這里我懷疑它是否能夠在沒有任何線程問題的情況下處理這些事件。 如果您有任何模式或內置API可以安全地處理此問題,請告訴我。

線程安全始終需要一個上下文 - 來自於什么

如果你的意思是+ =

對於+= ,這取決於事件的實現方式。 如果它被實現為類似字段的事件,即

public event SomeEventType EventReceived;

然后是的:它是線程安全的。 規范要求類字段事件的訪問器是線程安全的,盡管實現可能有所不同(例如,MS編譯器曾經使用lock(this)lock(typeof(DeclaringType)) ,但它現在使用Interlocked而不是)。

如果事件是手動實現的,即

public event SomeEventType EventReceived {
    add { ... }
    remove { ... }
}

然后,線程安全性完全由add / remove實現定義。

如果你的意思是調用

那么這是線程安全的,因為委托是不可變的,但請注意,這一切都發生在調用線程的單個線程上。 但是,常見的錯誤是在null測試中引入競爭條件:

if(EventReceived != null) EventReceived(this, someArgs);

以上不是線程安全的,因為從技術上講, EventReceived的值可以在測試后改變。 為了確保這不會出錯,它應該是:

var handler = EventReceived;
if(handler != null) handler(this, someArgs);

如果你的意思是處理程序

然后,線程安全性完全由各個處理程序定義。 例如,在UI應用程序中,必須檢查並切換到UI線程的處理程序。

引用C#規范

When compiling a field-like event, the compiler automatically creates 
storage to hold the delegate, and creates accessors for the event that 
add or remove event handlers to the delegate field. In order to be thread-safe, 
the addition or removal operations are done while holding the lock (§8.12)
on the containing object for an instance event, or the type object (§7.6.10.6)
for a static event.

底線是,如果EventReceived是像事件(非自定義實現)的字段,那么它的線程是安全的!

更新當前實現使用Interlocked來保證線程安全

在此輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM