问题描述
从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()
:
and Volatile.Write()
:
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背后的逻辑是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!