当前位置: 首页 > 知识库问答 >
问题:

对于c#中的易失性字段,实际保证的是什么?

方和豫
2023-03-14

我对. NET/C#的留档感到困惑,关于易失性关键字vs系统。线程。线程。VolatileRead/VolatileWrit系统。线程。易失性。读/写。我试图了解易失性字段的确切保证以及这些方法到底在做什么。

我认为volatile提供了发布/获取语义,但它提供了线程的文档。VolatileRead让我怀疑自己的理解是否正确。

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

添加volatile修饰符可以确保所有线程都能观察到任何其他线程按照执行顺序执行的volatile写入。无法保证从所有执行线程中看到的易失性写入的单一总顺序。

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

对于易失性字段,此类重新排序优化受到限制:

对易失性字段的读取称为易失性读取。易失性读取具有“获取语义”;也就是说,在指令序列中,它保证发生在对内存的任何引用之前,而对内存的任何引用发生在它之后。对易失性字段的写入称为易失性写入。易失性写入具有“释放语义”;也就是说,它保证在指令序列中写入指令之前的任何内存引用之后发生。

这些限制确保所有线程都将按照它们执行的顺序观察任何其他线程执行的易失性写入。符合要求的实现不需要提供从所有执行线程看到的易失性写入的单一总顺序。

同样,这看起来像volatile提供了发布/获取语义。

然后我看了看Thread的留档。https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.volatileread?view=netframework-4.8#System_Threading_Thread_VolatileRead_System_Int64__

读取字段的值。该值是计算机中任何处理器写入的最新值,无论处理器的数量或处理器缓存的状态如何。。。在多处理器系统上,volatieread获取任何处理器写入内存位置的最新值。这可能需要刷新处理器缓存。

用于Thread。VolatileWrite:

立即将值写入字段,以便计算机中的所有处理器都可以看到该值。

这看起来比单独的存储/加载界限(释放/获取)更严格,特别是关于刷新处理器缓存的部分,也就是说,比volatile更严格的保证。但同样的文件说:

在C#中,对字段使用volatile修饰符可以保证对该字段的所有访问都使用VolatileRead或VolatileWrite

所以我的问题是-对于存储缓冲区而言,volatile字段的保证是什么-只需释放/获取,或者使用更强的线程。VolatileRead/Write担保?还是我对volatile读/写的理解有误,这些都与volatile相同?

共有1个答案

孔鸿宝
2023-03-14
  1. 系统之间没有区别。穿线。线VolatileRead/VolatileWrite和系统。穿线。不稳定的读/写-这些都是相同的辅助方法,在读或写之前模拟完整的内存屏障(不需要MFENCE指令)。以下是内部实施:
public static void VolatileWrite(ref sbyte address, sbyte value)
{
  Thread.MemoryBarrier();
  address = value;
}

volatile变量在内存模型较弱的过时IA处理器体系结构(Itanium)上使用(-ed)获取/释放语义。

对于最流行的x86体系结构,volatile修饰符可以避免编译器优化,还可以使用前缀为lock的指令来保证一致性。

总而言之,编译器可能会使用各种技巧来遵守C#内存模型,其中规定:

 类似资料:
  • 我已经阅读了许多相互矛盾的信息(msdn,SO等),关于易失性和VoletleRead(ReadAcquireFence)。 我理解这些限制的内存访问重新排序含义——我仍然完全搞不清楚的是新鲜度保证——这对我来说非常重要。 msdn doc用于挥发性提及: (…)这样可以确保字段中始终存在最新的值。 挥发性字段的msdn文档提到: 对易失性字段的读取称为易失性读取。易失性读取具有“获取语义”;也就

  • 所有的中断函数都能正常工作,但是过程函数却让我很生气。 我会感激任何我没注意的把戏。

  • 我对易变语义几乎没有疑问 假设有三个线程T1、T2和T3,以及给定类的一个实例。 假设发生以下读/写操作序列: 我知道可以保证点9的T1将看到点7的值,点10的T1将看到点6的值(确切地说,至少和这个值一样最新)。 但是,这些说法是真的吗? Java内存模型保证,点11处的T1将看到至少与点5处的T3相同的最新值(来自T3或更实际的本地内存的值,但即使共享内存中有更实际的值,T1也可能看不到) 请

  • 我正在使用以下字段: 哪里 这样发布日期图安全吗?我的意思是,易失性字段意味着对一个字段的引用不会缓存在CPU寄存器中,并且在任何时候访问它都可以从内存中读取。 因此,我们不妨为映射的

  • 我已经读到,使引用变量易失性,并不会使其内部字段易失性。但我尝试了下面的示例,其中看起来易失性也应用于类的内部字段。 使用者java:-//字段“flag”设置为true的用户类。 MyRunnableThread1。java:- 在这里,我将“user”设置为volatile,而不是将其内部字段“flag”设置为volatile 子线程在“while(this.user.isFlag())”处连

  • 我正在使用rest assured进行API post调用,并在体内得到响应。然后,我需要接受这个响应,选择特定的字段值,并将它们存储为字符串,以便稍后与其他字符串对象进行比较。我很好地编写了jsonpath来获取顶级字段值(如id、status、type、country等),但当我必须进入返回的json数组中的一个对象时,我无法正确获取get()方法的格式。 下面是返回的Json示例: 下面是我