c# - C# 合并运算符的原子性

标签 c# atomic null-coalescing-operator

我今天在我们的代码库中遇到了一些单例代码,我不确定以下代码是否是线程安全的:

public static IContentStructure Sentence{ 
    get {
       return _sentence ?? (_sentence = new Sentence()); 
    }
}

这个语句等同于:

if (_sentence != null) {
       return _sentence;
}
else {
    return (_sentence = new Sentence());
}

我相信??只是一个编译器技巧,生成的代码仍然不是原子的。换句话说,两个或多个线程可以在将 _sentence 设置为新的 Sentence 并返回它之前发现 _sentence 为 null。

为了保证原子性,我们必须锁定那段代码:

public static IContentStructure Sentence{ 
    get {

       lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); }
    }
}

都对吗?

最佳答案

I ran into some singleton code today in our codebase

您的代码库中是否存在此类混淆代码?这段代码做同样的事情:

if (_s == null) 
    _s = new S();
return _s;

而且阅读起来容易一千倍。

I believe that ?? is just a compiler trick and that the resulting code is still NOT atomic

你是对的。 C# 对原子性做出以下保证:

Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.

空合并运算符不在该保证列表中。

To guarantee atomicity, we'd have to lock that bit of code:

lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); } } }    

天哪,没有。那会立即崩溃!

正确的做法是:

  • 停止尝试编写多线程代码。
  • 使用 Jon Skeet 在他关于单例的页面上记录的安全单例模式之一编写单例。
  • 使用Lazy<T>类。
  • 锁定专用于锁定该变量的对象。
  • 使用互锁比较交换进行原子测试和设置。

关于c# - C# 合并运算符的原子性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9420285/

相关文章:

c# - 接口(interface)顺序的意义

multithreading - thread::join() 在不应该阻塞时阻塞

c# - 将数组插入 SQL Server 数据库问题

c# - 在java中使用C# dll

c++ - 对原子结构和指针的误解

c# - 在 C# 8 中有没有更短的写法?

c# - ASP.NET MVC/C# - 空合并运算符、类型

c# - 空合并赋值运算符?

javascript - MVC - 单击时没有任何反应( View 中的 Jquery)

c - 访问静态初始化变量时是否应该使用屏障?