操作的原子性是由硬件而非软件引起的(好吧,在C++中也有“原子”变量,但这些仅在名称上是原子的,实际上是通过互斥锁和锁来实现的)。因此,基本上,C++原子和C原子做的事情是完全相同的。因此,只要类型兼容,就不会出现问题。并且C++11和C11原子类被设计为兼容。
显然,人们不理解原子操作和锁的工作原理,并需要进一步解释。请查看当前的内存模型以获取更多信息。
1)我们将从基础知识开始。什么是原子操作?为什么需要使用它?内存是如何工作的?
内存模型:将处理器视为几个独立的核心,每个核心都有自己的内存(缓存L1、L2和L3;实际上,L3缓存是共用的,但并不重要)。
为什么需要原子操作?
如果不使用原子操作,则每个处理器可能都有自己的变量“x”的版本,并且通常不会同步。无法确定它们何时会与RAM/L3缓存执行同步。
使用原子操作时,使用这样的内存操作,以确保与RAM/L3缓存(或所需的任何内容)同步——确保不同的核心可以访问相同的变量,并且不会具有各种不同的版本。
无论您使用C、C++还是其他语言-只要确保内存同步(读取、写入和修改),就不会出现任何问题。
2)好的,那么锁和互斥锁呢?
Mutexes通常与操作系统一起使用,并有队列,以确定下一个要执行的线程。相比原子操作,它们强制执行更严格的内存同步。通过原子操作,可以仅同步变量本身或更多,具体取决于请求/调用哪个功能。
3)假设我有atomic_bool,在不同语言(C/C++11)中是否可以互换使用?
通常,布尔值可以通过内存操作进行同步(从他们的角度来看,您只需同步单个字节的内存)。如果编译器知道硬件可以执行这种操作,那么只要使用标准,它们肯定会使用它们。
逻辑原子(任何T类型为错误大小/对齐的std::atomic )通过锁进行同步。在这种情况下,不太可能不同的语言可以交替使用它们-如果它们对这些锁使用不同的使用方法,或者由于某种原因一个决定使用锁,而另一个则得出结论它可以使用原子硬件内存同步......那么就会出现问题。
如果您在任何支持C/C ++的现代计算机上使用atomic_bool,则无疑可以在没有锁的情况下同步。
cancelled
使用的典型场景中 - 不需要同步。我会在自己的回答中更详细地描述这一点。看起来你在使用“同步”这个词时并不理解它的含义,以及何时需要使用它,何时不需要。 - RbMmvolatile
来防止该问题,并且这里的未定义行为是什么- 您可以展示具体的例子并解释如果我们在一个线程中使用循环do {.. } while (!cancelled);
,并在另一个线程中使用cancelled = true
会导致什么具体的未定义。我甚至在抽象语言层面上都看不到任何问题。关于原子性- 我想说的是,即使我们只使用值的两个状态- 0和非0,也不需要原子性。您能否用具体的例子展示 UB 或类似问题? - RbMm