简体   繁体   English

C#的空条件委托调用线程是否安全?

[英]Is C#'s null-conditional delegate invocation thread safe?

This is how I have always written event raisers; 这就是我一直写的事件提升者; for example PropertyChanged: 例如PropertyChanged:

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string name)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }

In the latest Visual Studio, however, the light bulb thingamabob suggested simplifying the code to this: 然而,在最新的Visual Studio中,灯泡thingamabob建议将代码简化为:

    private void RaisePropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

Although I'm always in favor of simplification, I wanted to be sure this was safe. 虽然我总是赞成简化,但我想确保这是安全的。 In my original code, I assign the handler to a variable to prevent a race condition in which the subscriber could become disposed in between the null check and the invocation. 在我的原始代码中,我将处理程序分配给变量以防止订阅者在空检查和调用之间处置的竞争条件。 It seems to me that the new simplified form would suffer this condition, but I wanted to see if anyone could confirm or deny this. 在我看来,新的简化形式将遭受这种情况,但我想看看是否有人可以确认或否认这一点。

它与它替换的代码(你的第一个例子)一样是线程安全的,因为它只是使用一个隐藏变量做同样的事情。

from MSDN: 来自MSDN:

The new way is thread-safe because the compiler generates code to evaluate PropertyChanged one time only, keeping the result in temporary variable. 新方法是线程安全的,因为编译器只生成一次评估PropertyChanged的代码,将结果保存在临时变量中。 You need to explicitly call the Invoke method because there is no null-conditional delegate invocation syntax PropertyChanged?(e). 您需要显式调用Invoke方法,因为没有空条件委托调用语法PropertyChanged?(e)。 There were too many ambiguous parsing situations to allow it. 有太多模糊的解析情况允许它。

https://msdn.microsoft.com/en-us/library/dn986595(v=vs.140).aspx https://msdn.microsoft.com/en-us/library/dn986595(v=vs.140).aspx

Internally .net framework uses interlock.CompareExchange when you subscribe for an event. 内部.net框架在订阅事件时使用interlock.CompareExchange。 This means you already has memory barrier there. 这意味着你已经有了记忆障碍。 To be thread safe you need to use Volatile.Read when accessing your event handler (it applies implicit aquire memory barrier) 要保证线程安全,您需要在访问事件处理程序时使用Volatile.Read(它应用隐式获取内存屏障)

Volatile.Read(ref PropertyChanged)?.Invoke(this, new PropertyChangedEventArgs(name)) Volatile.Read(ref PropertyChanged)?. Invoke(this,new PropertyChangedEventArgs(name))

Source: CLR via C# 来源: CLR通过C#

Other source: https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/ 其他来源: https//codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/

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

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