是 C# 6 .(猫王操作)线程安全?如果是这样,如何

本文关键字:如果 如何 安全 线程 猫王 操作 | 更新日期: 2023-09-27 18:37:13

提前道歉:这个问题来自一个试图学习高级 C# 的硬核、未改革的C++开发人员。请考虑以下事项:

if (myUserDefinedObject != null)
{
    myUserDefinedObject.ToString();
}

这显然不是线程安全的。另一方面,我看过两个教程说?。(空条件运算符或"猫王运算符")例如,

myUserDefinedObject?.ToString();

线程安全。除非编译器在幕后(颤抖)包裹着 [mutex?] 锁,否则我不明白这怎么可能是真的。如果这个成语是线程安全的,有人可以指出我如何实现的技术描述吗?如果它不是线程安全的,有没有人有一个参考实际上说它不是?

是 C# 6 .(猫王操作)线程安全?如果是这样,如何

我想

澄清BJ Myers的(正确)答案。

在 C# 中,可以将事件视为委托类型的字段 - 就像可以将属性视为属性类型的字段一样 - 并且该"字段"的值可以为 null。如果您不幸在一个线程上修改了事件处理程序,而另一个线程正在尝试调用它,则可能会遇到以下情况:

if (this.SomeEvent != null) 
    this.SomeEvent( ... );

不是线程安全的。该值可能会发生变化,以便在检查之前为非 null,在检查后为 null,并且程序崩溃。

使这个"线程安全"的常用方法(我建议使用该术语)是将值复制到本地,然后测试本地的 null。 这样做的好处是不会因空取消引用而崩溃。但是,聪明的开发人员会注意到还有一场比赛!序列可以是

  • 缓存在线程 A 上的非空事件处理程序
  • 事件处理程序在线程 B 上设置为 null
  • 事件处理程序所需的状态在线程 B 上被销毁
  • 事件处理程序在线程 A 上运行并严重死亡

所以从这个意义上说,这种模式不是"线程安全的"。 如果您处于这种不幸的位置,您有责任确保实现适当的线程逻辑,以便不会发生这种情况。 你可以随心所欲地这样做。如果你想要能够在一个线程上调用事件处理程序,同时在另一个线程上改变事件,那么你必须付费以确保它的安全,或者处理竞争条件错误。

我个人会像瘟疫一样避免这种情况,但我不够聪明,无法编写正确的多线程代码。

现在,关于实际问题:

some_expression ?. ToString();

temp = some_expression
temp == null ? null : temp.ToString()

您认为后一种代码是"线程安全的"吗?

来自 MSDN(强调我的):

null 条件成员访问的另一个用途是以线程安全的方式调用委托,代码要少得多。旧方法需要如下代码:

var handler = this.PropertyChanged;
if (handler != null)
    handler(…)

新方法要简单得多:

PropertyChanged?.Invoke(e)

新方法是线程安全的,因为编译器生成代码来仅计算一次 PropertyChanged,将结果保留在临时变量中

因此,这里不涉及锁定 - 线程安全是通过创建一个局部临时变量来强制执行的,这可以防止不同的线程在 null 检查和其他一些操作之间修改该变量。

相关文章: