强制记忆顺序

时间:2014-03-01 12:39:47

标签: c order-of-execution

如果存在指针“A”和“B”,则要求在对“B”的任何写入可见之前,应使任何对“A”的写入可见。如果我不被允许使用锁,并且如果我不允许将这些变量声明为“volatile”,那么以下代码是否会保证满足上述要求?

volatile temp;

*A = value1;
temp = *A;

if (temp == value1) {
    *B = value2
}

4 个答案:

答案 0 :(得分:3)

您需要使用内存屏障或围栏:请参阅http://en.wikipedia.org/wiki/Memory_barrier

在Linux内核中,您可以使用rmb()wmb()来电。

pthreads下,您可以使用pthread_barrier_wait(),但这似乎不在我的pthreads联机帮助页中。

在MSVC上,查看Force order of execution of C statements? - 这也有一些很好的一般信息。

如果找到'原子'库,通常会包含屏障函数。

答案 1 :(得分:2)

答案很简单。你不能。重新排序可能因为:

  • 编译器将决定重新排序(允许这样做,虽然这取决于编译器标志等);
  • 处理器将决定重新排序。如果处理器足够复杂,它肯定会这样做。

要强制进行内存排序,您需要同步。不幸的是,这里有很多方法。每种方法都有自己的优点和缺点。根据您的情况,您需要选择一些。

答案 2 :(得分:1)

我认为C编译器重新排序您的示例代码是完全合法的:

volatile temp;

old_b = *B;
*B = value2;    
*A = value1;
temp = *A;

if (temp != value1) {
    *B = old_b;
}

这样的事情可能会更好:

volatile temp;

temp = value1;
*A = temp;
temp = value2;
*B = temp;

但即使您知道B的存储指令出现在A的存储指令之后,这仍然不能保证其他线程“看到”该顺序的修改。这将取决于缓存同步,基本上是不可预测的。您需要内存屏障或锁定机制才能使其可靠运行。

答案 3 :(得分:0)

不,它不会。并且你无法用易失性和简单的C结构来实现它。只要您的程序正常工作(并且其他任何人都被诅咒!),编译器可以自由地重新排序您的代码。

所以问题是:你还可以考虑其他什么选择?例如,如果唯一的要求是另一个任务永远不会看到无序更新,则可以通过在设置A和B之间进行任何系统调用来有效地保证。即使在远程内存位置调用库函数也可能会工作。您真正需要做的就是超越尽可能长的管道。但这可能需要一段时间......

这让我想到了一个问题:你打算如何测试?它的时间关键性如何?

可能需要更多信息才能真正回答这个问题。