繁体   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