假设我们有两个线程。一个“开始”,一个等待“开始”以产生某种东西。
此代码是否正确,或者我是否可以因为缓存或类似原因而出现“无限循环”?
std::atomic_bool canGo{false};
void producer() {
while(canGo.load(memory_order_relaxed) == false);
produce_data();
}
void launcher() {
canGo.store(true, memory_order_relaxed);
}
int main() {
thread a{producer};
thread b{launcher};
}
如果这段代码不正确,有没有办法在标准 C++ 中刷新/使缓存失效?
最佳答案
像这样的开始信号通常会响应您希望目标看到的一些内存变化。
换句话说,您通常希望为此类信号提供release/acquire 语义。
这可以通过在存储上使用 memory_order_release
和在加载上使用 memory_order_acquire
来完成,或者通过放置一个release fence 在松弛存储之前和获取围栏之后松弛加载,以便信号发送者在存储之前完成的内存操作对信号接收者可见(参见例如,https://preshing.com/20120913/acquire-and-release-semantics/ 或 C/C++ 标准)。
我记得栅栏的顺序是,据我所知,内核之间的共享内存操作实际上是 hardware implemented buffered IO that follows a protocol,释放栅栏应该类似于输出缓冲区刷新,而获取栅栏类似于输入缓冲区刷新/同步。
现在,如果您在发出宽松存储之前刷新核心的内存操作输出缓冲区,那么当目标核心看到宽松存储时,前面的内存操作消息必须对它可用并且它需要的一切在其内存中查看这些内存更改是在看到信号存储后将它们与获取栅栏同步。
关于c++ - 放宽顺序作为信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56906486/