c# - c# 中的 volatile 字段实际上保证了什么?

标签 c# multithreading volatile

我对有关 volatile 的 .NET/C# 文档感到困惑关键字 vs System.Threading.Thread.VolatileRead/VolatileWriteSystem.Threading.Volatile.Read/Write .我试图了解 volatile 字段的确切保证以及这些方法究竟在做什么。

我以为volatile提供发布/获取语义,但提供 Thread.VolatileRead 的文档/VolatileWrite让我怀疑我的理解是否真的正确。

这是 volatile 的语言引用:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/volatile

Adding the volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order in which they were performed. There is no guarantee of a single total ordering of volatile writes as seen from all threads of execution.



到目前为止是有道理的。这是语言规范:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#volatile-fields

For volatile fields, such reordering optimizations are restricted:

A read of a volatile field is called a volatile read. A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence. A write of a volatile field is called a volatile write. A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

These restrictions ensure that all threads will observe volatile writes performed by any other thread in the order in which they were performed. A conforming implementation is not required to provide a single total ordering of volatile writes as seen from all threads of execution.



同样,这看起来像 volatile提供释放/获取语义。

但后来我查看了 Thread.VolatileRead 的文档:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.volatileread?view=netframework-4.8#System_Threading_Thread_VolatileRead_System_Int64__

Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. ... On a multiprocessor system, VolatileRead obtains the very latest value written to a memory location by any processor. This might require flushing processor caches.



对于 Thread.VolatileWrite:

Writes a value to a field immediately, so that the value is visible to all processors in the computer.



这看起来比单独的存储/加载栅栏(释放/获取)更严格,特别是关于刷新处理器缓存的部分,即比 volatile 更严格的保证.但随后同一份文件说:

In C#, using the volatile modifier on a field guarantees that all access to that field uses VolatileRead or VolatileWrite



所以我的问题是 - volatile 的保证是什么?与存储缓冲区相关的字段 - 只是释放/获取,还是更强的 Thread.VolatileRead/Write 保证?或者是我对VolatileRead/Write的理解错误,这些与 volatile 相同?

最佳答案

  • System.Threading.Thread.VolatileRead/VolatileWrite之间没有区别和 System.Threading.Volatile.Read/Write - 这些是在读取或写入之前模拟完整内存屏障的相同辅助方法(不需要 MFENCE 指令)。这是内部实现:

  • public static void VolatileWrite(ref sbyte address, sbyte value)
    {
      Thread.MemoryBarrier();
      address = value;
    }
    
  • 一个 volatile variable uses(-ed) 在过时的 IA 处理器架构 (Itanium) 上使用较弱的内存模型获取/释放语义。
  • 使用最流行的 x86 架构,volatile修饰符避免编译器优化,也可以使用带有 lock 的指令前缀以保证一致性。

  • 总而言之,编译器可能会使用各种技巧来遵守 C# memory model ,其中指出:

    1. No reads or writes can move before a volatile read or after a volatile write
    2. All writes have the effect of volatile write

    关于c# - c# 中的 volatile 字段实际上保证了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59726742/

    相关文章:

    c# - 需要有关属性(property)使用权的进修类(class)

    windows - 在 Windows 中强制上下文切换

    java - 如何确保所有生成的线程都已完成以便处理可以继续?

    C# volatile double

    c# - 如何根据分钟舍入小时数(如果分钟<30,小时+0,否则小时+1)?

    c# - Http post 在 Postman 中有效,但在 C# 中使用 HttpClient 无效

    c# Winform 更新表单的最佳方式?

    java - Java实际上是否并行运行线程

    c# - 间接访问需要 volatile 吗?

    c++ - 通过 volatile 引用/指针访问声明的非 volatile 对象是否赋予所述访问 volatile 规则?