【问题标题】:Is the ternary operator (?:) thread safe in C#?C# 中的三元运算符 (?:) 线程安全吗?
【发布时间】:2012-10-03 22:48:44
【问题描述】:

考虑以下两种在currentPrice100 之间获得更大数字的替代方案...

int price = currentPrice > 100 ? currentPrice : 100

int price = Math.Max(currentPrice, 100)

我提出这个问题是因为我在考虑currentPrice 变量可以被其他线程编辑的上下文。

在第一种情况下...price 可以得到一个低于100 的值吗?

我正在考虑以下问题:

if (currentPrice > 100) {
    //currentPrice is edited here.
    price = currentPrice;
}

【问题讨论】:

    标签: c# thread-safety ternary-operator


    【解决方案1】:

    理论上,currentPrice 会被读取两次。一次比较,一次分配。

    实际上,编译器可能会缓存对变量的访问。我不了解 C#,但在 x86 上使用 C++:

    MOV AX, [currentPrice]
    MOV BX, 100 ;cache the immediate
    CMP AX, BX
    JLE $1      ;if(currentPrice > 100){
    MOV AX, BX
    $1:         ;}
    MOV [BP+price], AX ;price is on the stack.
    

    除非 currentPrice 被声明为 volatile,否则 Java 字节码中会发生相同的 load-once 优化。

    因此,理论上,它可能会发生。实际上,在大多数平台上,它不会,但你不能指望它。

    【讨论】:

      【解决方案2】:

      不是 C# 方面的专家,但即使 var++ 也不是线程保存,因为可能会转换为从汇编中的寄存器读取/写入。

      三元运算符要复杂得多。它有 3 个部分,而每个部分都可以无限大(例如调用某个函数)。因此,很容易得出三元运算符不是线程安全的结论。

      【讨论】:

      • +1;恐怕 x86 不会让你 INCrement 内存位置,所以它翻译为移动到注册表/增量/移动到内存组合。
      【解决方案3】:

      正如其他人所说,它可能会被缓存,但语言不需要它。

      如果您需要无锁线程安全分配,您可以使用Interlocked.CompareExchange。但鉴于示例,我会选择更粗粒度的锁定策略。

      【讨论】:

        【解决方案4】:

        它不是线程安全的。

        ?: 只是普通if 的快捷方式,因此您的if 样本相当于? 之一 - 如果此代码之外没有锁定,您可以获得低于 100 的价格。

        【讨论】:

        • 几分钟内得到相反的答案? :D
        • @dotNETbeginner :) 很好的观察。当我读到我的第一个答案时,我也想给我 -10。
        猜你喜欢
        • 1970-01-01
        • 2011-11-09
        • 1970-01-01
        • 2012-05-20
        • 2015-12-01
        • 2010-12-15
        • 2015-12-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多