c++ - 互斥锁如何确保变量的值在内核之间保持一致?

标签 c++ multithreading mutex

如果我想要从一个线程写入并从另一个线程读取的单个 int,我需要使用 std::atomic,以确保其值在内核之间保持一致,无论读取和写入它的指令在概念上是否是原子的。如果我不这样做,则可能是读取核心在其缓存中具有旧值,并且不会看到新值。这对我来说很有意义。

如果我有一些无法以原子方式读取/写入的复杂数据类型,我需要使用一些同步原语来保护对它的访问,例如 std::mutex。这将防止对象进入(或被读取)不一致的状态。这对我来说很有意义。

对我来说没有意义的是互斥锁如何帮助解决原子解决的缓存问题。它们的存在似乎只是为了防止对某些资源的并发访问,而不是将包含在该资源中的任何值传播到其他核心的缓存。我是否遗漏了一些处理这个问题的语义?

最佳答案

对此的正确答案是魔法小 Sprite - 例如。它只是工作。每个平台的 std::atomic 实现必须做正确的事情。

正确的事情是三个部分的组合。

首先,编译器需要知道它不能跨边界移动指令[事实上在某些情况下它可以,但假设它不会]。

其次,缓存/内存子系统需要知道 - 这通常使用内存屏障来完成,尽管 x86/x64 通常具有如此强大的内存保证,因此在绝大多数情况下这不是必需的(这是一个很大的耻辱因为错误的代码实际上出错了)。

最后,CPU 需要知道它不能重新排序指令。现代 CPU 在重新排序操作方面非常激进,并确保在单线程情况下这是不引人注意的。他们可能需要更多提示,这在某些地方不会发生。

对于大多数 CPU,第 2 部分和第 3 部分归结为同一件事 - 内存屏障意味着两者。第 1 部分完全在编译器内部,由编译器编写者来解决。

见 Herb Sutters 演讲 'Atomic Weapons'了解更多有趣的信息。

关于c++ - 互斥锁如何确保变量的值在内核之间保持一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17046558/

相关文章:

java - 将不同线程中的日志消息分组

c++ - boost::thread 和 std::unique_ptr

c# - 为什么要使用 Mutex 来锁定?

c++ - 如何获取 DLL 中的函数列表(托管和非托管)?

MyProject_p.obj 中的 C++ 链接错误无法解析的外部符号

c++ - C/C++ 中的指针帮助

multithreading - 哪个更有效,基本互斥锁或原子整数?

c++ - 错误 C4018 与 vector 大小 () 在 c++

java - 使用notify将线程从其状态唤醒

multithreading - 为什么需要空互斥体?