简体   繁体   English

C#订阅所​​有对象的相同事件处理程序是否安全

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

I have a situation in my project where i have connect to multiple server and listen for events. 我的项目中有一个情况,我连接到多个服务器并监听事件。 Whenever a event received from the server, Handler should add the event to the common queue for processing. 每当从服务器收到事件时,Handler都应将事件添加到公共队列进行处理。 All connections should add received events to the queue. 所有连接都应将收到的事件添加到队列中。

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
}

Here i doubt that whether it can be able to handle those events without any threading issues. 在这里我怀疑它是否能够在没有任何线程问题的情况下处理这些事件。 Please let me know if you have any patterns or built in APIs to handle this safely. 如果您有任何模式或内置API可以安全地处理此问题,请告诉我。

Thread-safety always needs a context - a from what . 线程安全始终需要一个上下文 - 来自于什么

If you mean the += 如果你的意思是+ =

For the += , that depends on how the event is implemented. 对于+= ,这取决于事件的实现方式。 If it is implemented as a field-like event, ie 如果它被实现为类似字段的事件,即

public event SomeEventType EventReceived;

then yes: it is thread-safe. 然后是的:它是线程安全的。 The specification requires that the accessors for field-like events are thread-safe, although the implementation can vary (for example, the MS compiler used to use lock(this) or lock(typeof(DeclaringType)) , however it now uses Interlocked instead). 规范要求类字段事件的访问器是线程安全的,尽管实现可能有所不同(例如,MS编译器曾经使用lock(this)lock(typeof(DeclaringType)) ,但它现在使用Interlocked而不是)。

If the event is implemented manually, ie 如果事件是手动实现的,即

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

Then the thread-safety is defined entirely by the add / remove implementations. 然后,线程安全性完全由add / remove实现定义。

If you mean the invoke 如果你的意思是调用

Then that is thread-safe since delegates are immutable, but note that it all happens on the single thread that invokes the thread. 那么这是线程安全的,因为委托是不可变的,但请注意,这一切都发生在调用线程的单个线程上。 However, a common mistake is to introduce a race condition in a null test: 但是,常见的错误是在null测试中引入竞争条件:

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

The above is not thread-safe, since technically the value of EventReceived can change after the test. 以上不是线程安全的,因为从技术上讲, EventReceived的值可以在测试后改变。 To ensure this does not error, it should be: 为了确保这不会出错,它应该是:

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

If you mean the handlers 如果你的意思是处理程序

Then the thread-safety is defined entirely by the individual handlers. 然后,线程安全性完全由各个处理程序定义。 For example, in UI applications it is the handlers that must check for, and switch to, the UI thread. 例如,在UI应用程序中,必须检查并切换到UI线程的处理程序。

Quoting from C# spec 引用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.

Bottom line is if the EventReceived is field like event(non custom implementation) then its thread safe! 底线是,如果EventReceived是像事件(非自定义实现)的字段,那么它的线程是安全的!

Update Current implementation uses Interlocked for thread safety 更新当前实现使用Interlocked来保证线程安全

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM