Volatile.Read和Volatile.Write背后的逻辑是什么? [英] What is the logic behind Volatile.Read and Volatile.Write?

查看:270
本文介绍了Volatile.Read和Volatile.Write背后的逻辑是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从MSDN中, Volatile.Read()


读取值的领域。在需要它的系统上,插入一个
内存屏障,以防止处理器按以下方式重新排序内存
的操作:如果在此方法之后在
的代码中出现了读取或写入操作,则处理器将无法移动之前此方法。


Volatile.Write()


将值写入字段。在需要它的系统上,插入
内存屏障,以防止处理器按以下方式重新排序内存
的操作:如果在代码中此方法
之前出现了读取或写入操作,则处理器将无法移动之后此方法。


我想我可以理解的使用情况Volatile.Read() Volatile.Write(),并且看到了很多示例来说明这两种方法为何有助于确保程序的正确性。 / p>

但是我仍然想知道,这些规则背后的逻辑是什么?



Volatile.Read()为例,为什么需要之后不能在之前移动,但是不需要在之前操作吗?



Volatile.Write()



谢谢!

解决方案

关于易失性读取和易失性写入的保证确保了,如果一个线程使用易失性写入来表示已完成某事,然后另一个线程使用易失性读取来注意到该事已发生完成后,第二个线程将看到这些东西的全部效果。



例如,假设 Thread1 初始化对象 A ,然后对 flag 进行易失性写入以表明已完成。初始化对象 A 的字段所涉及的所有内存操作都发生在代码中的标志设置之前。保证是这些在易失性写入后不能移动到 flag ,因此,当在内存中设置该标志时,整个初始化对象都在内存中,而其他线程可以看到它。



现在让我们说 Thread2 正在等待该对象。它具有易读性,它看到设置了 flag ,然后读取 A 的字段,并根据它已经阅读。这些读取操作发生在代码中的易失性读取之后,并且易失性读取保证确保它们将在内存中进行易失性读取之后发生,因此保证 Thread2 可以看到完全初始化的对象 A 字段,而不是对象之前不存在的任何字段。



因此:写道 Thread1 在易失性地写入 flag 之前确实进入了内存,显然,它必须在 Thread2 可以易失性地读取它,然后在 Thread2 中进行以下读取,因此它会看到正确初始化的对象。



这就是为什么写操作不能延迟到易失性写之后,而读不能在易失性读之前上移的原因。反之亦然吗?



好吧,在看到后,可以说 Thread2 A 被初始化,执行一些工作并将其写入 Thread1 用于确定如何初始化 A 。保证在之后 Thread2 看到 A 完成后,这些写操作才会在内存中发生,并且保证 Thread1 对这些位置的读取肯定在之前 标志发生设置在内存中,因此保证 Thread2 的写操作不会干扰初始化工作。


From MSDN, Volatile.Read():

Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method.

and Volatile.Write():

Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method.

I think I can understand the using scenarios of Volatile.Read() and Volatile.Write(), and have seen many examples explaining why these two methods help ensuring the correctness of program.

But I still wonder, what is the logic behind these rules?

Take Volatile.Read() as example, why it requires operations after it cannot be moved before it, but does not require anything from operations before it?

And also why it's opposite to Volatile.Write()?

Thank you!

解决方案

The guarantees around volatile read and volatile write ensure that if one thread uses a volatile write to indicate that something is done, and then another thread uses a volatile read to notice that that something is done, then the second thread will see the full effects of that something.

For instance, lets say that Thread1 initializes object A, and than does a volatile write to a flag indicating that it's done. All of the memory operations involved in initializing the fields of object A occur before the flag setting in the code. The guarantee is that these "cannot be moved after the volatile write" to flag, so by the time the flag is set in memory, the whole initialized object is in memory where other threads can see it.

Now lets says that Thread2 is waiting for that object. It has a volatile read that sees flag get set, and then reads the fields of A and makes decisions based on what it has read. Those read operations occur after the volatile read in the code, and the volatile read guarantee ensures that they will occur after the volatile read in memory, so that Thread2 is guaranteed to see the fully initialized fields of object A, and not anything that existed before it.

So: The writes that Thread1 does go out to memory before the volatile write to flag, which obviously must go out to memory before Thread2 can volatile read it, and the following reads in Thread2 happen after that so it sees the properly initialized object.

That's why writes can't be delayed past volatile writes, and reads can't be moved up before volatile reads. What about vice versa?

Well, lets say that Thread2, after it sees that A is initialized, does some work and writes it to some memory that Thread1 is using to decide how to initialize A. Those writes are guaranteed not to happen in memory until after Thread2 sees that A is done, and the reads that Thread1 makes to those locations are guaranteed to happen before the flag is set in memory, so Thread2's writes are guaranteed not to interfere with the initialization work.

这篇关于Volatile.Read和Volatile.Write背后的逻辑是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆