尝试理解 Thread.MemoryBarrier() 和上下文切换之间的关系
由于看起来上下文切换可能发生在指令执行的任何时候,我现在想知道为什么代码“部分有问题”(这两条指令)有意义,如果上下文切换可以在任何指令之间发生并且我们可能在不同的CPU上第二条指令中的核心。
void B()
{
Thread.MemoryBarrier(); // Barrier 3
if (_complete)
{
//PART IN QUESTION
Thread.MemoryBarrier(); // Barrier 4
Console.WriteLine (_answer);
//END PART IN QUESTION
}
}
这里关于 MemoryBarrier 的描述似乎没有提供保证 MemoryBarrier 调用后不会切换CPU。
(这与这个问题相关)
Since it appears that context switch may happen at any point in execution of instructions I am now wondering why code "in part in question" (those 2 instructions) makes sense, if context switch can happen between any instructions and we may be on different CPU core in second instruction.
void B()
{
Thread.MemoryBarrier(); // Barrier 3
if (_complete)
{
//PART IN QUESTION
Thread.MemoryBarrier(); // Barrier 4
Console.WriteLine (_answer);
//END PART IN QUESTION
}
}
Description on MemoryBarrier here doesn't appear to give guarantees MemoryBarrier that CPUs won't be switched after calling it.
(this is related to this question)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
无法保证
MemoryBarrier
周围是否会发生上下文切换。这些是正交概念。There are no guarantees that a context switch will or won't happen around a
MemoryBarrier
. These are orthogonal concepts.没有什么。 MemoryBarriers 不会阻止上下文切换(或代码的原子执行)。
至于您的另一个问题,为什么需要屏障 4:
在上一个问题的示例代码中,如果屏障 4 不存在,C# 编译器、CLR 或 CPU 可能会在完成的变量之前重新排序答案变量的读取。即实际运行的代码可能类似于:
Console.WriteLine() 之前的屏障将阻止在读取
_completed
之前读取_answer
但请记住,代码示例仅为 void B() 中的代码提供了这一保证(前提是 A() 仅运行一次)
因此,除非A 和 B 串行运行,代码不提供任何锁定/通知,以便 B 始终打印 123。 A() 和 B() 可以在执行过程中的任何时候交错/中断 - 您无法控制谁可以访问运行时。
无论您以哪种顺序启动 2 个线程,都不能保证 B() 在 A() 之后运行。(尽管在代码中的其他地方,您可以先启动 A() 并在启动 B 之前显式等待它完成() 当然)
Nothing. MemoryBarriers does not prevent context switching, (or atomic execution of your code).
As to your other question, why Barrier 4 is needed:
In the example code from the previous question, the C# compiler, CLR or the CPU might reorder reading of the answer variable before the completed variable if barrier 4 was not there. i.e. the code that actually runs could be similar to:
A barrier before the Console.WriteLine() will prevent reading
_answer
before reading_completed
But keep in mind that the code example only provides this one guarantee about the code in void B() (provided A() is run only once )
So, unless A and B are run serially, the code does not provide any locking/notification such that B will always print 123. A() and B() could be interleaved/interrupted any time in its execution - you have no control over who gets to run when.
There is no guarantee that B() runs after A(), no matter which order you started the 2 threads in. (Though somewhere else in the code , you could start A() first and wait explicitly for it to finish before starting B() ofcourse)