C# 内存模型和非 volatile 变量在其他线程创建之前初始化

标签 c# java multithreading synchronization volatile

我有一个与 C# 内存模型和线程相关的问题。如果没有 volatile 关键字,我不确定下面的代码是否正确。

public class A {
  private int variableA = 0;

  public A() {

    variableA = 1;

    Thread B = new Thread(new ThreadStart(() => printA())).Start();
  }

  private void printA() {
    System.Console.WriteLine(variableA);
  }
}

我担心的是,是否可以保证线程 B 在不使用 volatile 的情况下看到值为 1 的变量 A?在主线程中,我只在构造函数中将 1 分配给 variableA。之后我不再接触变量 A,它仅在线程 B 中使用,因此可能不需要锁定。

但是,是否保证主线程会刷新他的缓存并将变量A的内容写入主内存,以便第二个线程可以读取新分配的值?

另外,是否保证第二个线程会从主存中读取变量A的内容?可能会发生一些编译器优化,线程 B 可以从缓存而不是主内存中读取 variableA 的内容吗?当指令的顺序改变时,可能会发生这种情况。

可以肯定的是,将 volatile 添加到 variableA 声明将使代码正确。但是,有必要吗?我问是因为我在构造函数中写了一些带有一些非 volatile 变量初始化的代码,这些变量稍后会被一些 Timer 线程使用,我不确定它是否完全正确。

Java 中的相同代码呢?

谢谢,米哈尔

最佳答案

有很多地方会创建隐式内存屏障。这是其中之一。启动线程会创建完整的障碍。因此,对 variableA 的写入将在线程启动之前提交,并且第一次读取将从主内存获取。当然,在 Microsoft 的 CLR 实现中,这有点有争议,因为写入已经具有易变的语义。但是 ECMA 规范中没有做出相同的保证,因此从理论上讲,Mono 实现在这方面可能会有不同的行为。

My concern is if it is guaranteed that the Thread B will see variableA with value 1 without using volatile?

在这种情况下……是的。但是,如果您继续在第二个线程中使用 variableA,则无法保证在第一次读取后它会看到更新。

But, is it guaranteed that the main thread will flush his cache and write the variableA contents to the main memory, so the second thread can read the newly assigned value?

是的。

Additionally, is it guaranteed that the second thread will read the variableA contents from the main memory?

是的,但仅限于第一次阅读。

For sure, adding volatile to the variableA declaration will make the code correct. But, is it neccessary?

在这个非常具体和狭窄的案例中……不。但是,通常建议您在这些情况下使用 volatile 关键字。随着场景变得更加复杂,它不仅可以使您的代码线程安全,而且还有助于记录该字段将被多个线程使用并且您已经考虑过使用锁的含义这一事实 -免费攻略。

关于C# 内存模型和非 volatile 变量在其他线程创建之前初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3595672/

相关文章:

c# - 将按钮插入富文本 block

c# - 请求被中止 : Could not create SSL/TLS secure channel for HttpWebRequest

java - SEAM session 还是 session 作用域 bean?

java - 使用 Java 日志框架的死锁

windows - 为什么我要使用 "Both"COM 线程模型而不是 "Free"?

c - 使用互斥体的 Pthread 同步未正确同步单词

c# - C#中的任务栈分配在哪里?

c# - 以特定模式格式化日期字符串

java - 何时使用 BindingAdapter,何时使用 MVVM 中的 liveData 或 observable 字段?

c# - 控制台应用程序中的 Application.Current "null"