【发布时间】:2016-11-22 02:32:45
【问题描述】:
来自Wikipedia的以下实现:
volatile unsigned int produceCount = 0, consumeCount = 0;
TokenType buffer[BUFFER_SIZE];
void producer(void) {
while (1) {
while (produceCount - consumeCount == BUFFER_SIZE)
sched_yield(); // buffer is full
buffer[produceCount % BUFFER_SIZE] = produceToken();
// a memory_barrier should go here, see the explanation above
++produceCount;
}
}
void consumer(void) {
while (1) {
while (produceCount - consumeCount == 0)
sched_yield(); // buffer is empty
consumeToken(buffer[consumeCount % BUFFER_SIZE]);
// a memory_barrier should go here, the explanation above still applies
++consumeCount;
}
}
表示必须在访问缓冲区的行和更新Count 变量的行之间使用内存屏障。
这样做是为了防止 CPU 重新排序栅栏上方的指令以及栅栏下方的指令。 Count 变量在用于索引缓冲区之前不应递增。
如果不使用栅栏,这种重新排序不会违反代码的正确性吗? CPU 在用于索引缓冲区之前不应执行 Count 的增量。 CPU在指令重排序时是否不考虑数据依赖性?
谢谢
【问题讨论】:
-
@user3286661:这意味着没有内存屏障可以使代码高于定义良好的C++。它对回答没有帮助,它解释了为什么你的问题的前提是有缺陷的。
-
@user3286661 我们不关心性能,对吧?这只是关于正确性。 (因为在
sched_yield上运行的代码的性能会很糟糕。)这必须是伪核心代码或特定于平台的代码。volatile如何与内存屏障和线程交互没有可移植的规则。 -
问题是关于内存屏障的概念。我们不关心性能。
-
@DavidSchwartz 维基百科示例是用伪代码编写的,看起来真的很像 Java。并且在参考资料和链接中多次提到 Java 而没有其他语言。可以安全地假设它是类似 Java 的 volatile ,它提供了额外的保证。
-
@Revolver_Ocelot 是的,Java 的内存模型在这方面和 C++ 是一样的。
标签: multithreading concurrency operating-system producer-consumer memory-barriers