【问题标题】:Is C#'s null-conditional delegate invocation thread safe? [duplicate]C# 的空条件委托调用线程安全吗? [复制]
【发布时间】:2016-04-05 12:04:05
【问题描述】:

这就是我一直以来编写事件引发器的方式;例如 PropertyChanged:

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

然而,在最新的 Visual Studio 中,灯泡 thingamabob 建议将代码简化为:

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

虽然我一直支持简化,但我想确保这样做是安全的。在我的原始代码中,我将处理程序分配给一个变量,以防止订户可能在空检查和调用之间被处置的竞争条件。在我看来,新的简化形式会遇到这种情况,但我想看看是否有人可以确认或否认这一点。

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      来自 MSDN:

      新方法是线程安全的,因为编译器生成代码 只评估一次 PropertyChanged,将结果保存在 临时变量。您需要显式调用 Invoke 方法 因为没有空条件委托调用语法 属性已更改?(e)。模棱两可的解析情况太多 允许它。

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

      【讨论】:

        【解决方案3】:

        当您订阅事件时,.net 框架在内部使用 interlock.CompareExchange。这意味着您那里已经存在内存障碍。为了线程安全,您需要在访问事件处理程序时使用 Volatile.Read(它应用隐式获取内存屏障)

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

        来源:CLR via C#

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多