2

由于看起来上下文切换可能发生在指令执行的任何时候,我现在想知道为什么代码“部分有问题”(这两条指令)是有意义的,如果上下文切换可以在任何指令之间发生并且我们可能在不同的 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。

(这与这个问题有关

4

2 回答 2

3

不能保证上下文切换会或不会发生在MemoryBarrier. 这些是正交概念。

于 2011-08-31T17:12:33.127 回答
2

什么保证在 Thread.MemoryBarrier() 调用后不会发生上下文切换?

没有。MemoryBarriers 不会阻止上下文切换(或代码的原子执行)。

至于你的另一个问题,为什么需要屏障 4:

在上一个问题的示例代码中,如果屏障 4 不存在,C# 编译器、CLR 或 CPU 可能会在完成变量之前重新排列对 answer 变量的读取。即实际运行的代码可能类似于:

Thread.MemoryBarrier();    // Barrier 3
int tmpanswer = _answer;
if (_complete)
{

  Console.WriteLine (tmpanswer);
}

Console.WriteLine() 之前的障碍将阻止读取_answer前读取_completed

但请记住,代码示例仅提供有关 void B() 中代码的这一保证(前提是 A() 仅运行一次

  • 如果 _complete 变量为 true ,则 Console.WriteLine 将写出 123 而不是 0。

因此,除非 A 和 B 连续运行,否则代码不会提供任何锁定/通知,因此 B 将始终打印 123。 A() 和 B() 可以在其执行的任何时间交错/中断 - 您无法控制谁什么时候跑。

不能保证 B() 在 A() 之后运行,无论您以哪个顺序启动 2 个线程。(尽管在代码中的其他地方,您可以先启动 A() 并明确等待它完成,然后再启动 B () 当然)

于 2011-08-31T17:39:53.717 回答