在 BSD 提供的原子操作中(在 atomic(9) 手册页中给出),有 atomic_load_acq_int()
和 atomic_store_rel_int()
。在寻找其他操作系统的等效项时(例如,通过阅读 Mac OS X 的 atomic(3) 手册页,Solaris 的 atomic_ops(3C) 手册页,和 Windows 的 Interlocked*()
函数),似乎没有任何(明显的)等价物用于原子地读/写 int
。
这是因为它暗示那些为 int
读/写的操作系统默认保证是原子的吗? (或者你必须在 C/C++ 中使用 declare them volatile
吗?)
如果不是,那么如何在这些操作系统上对 int
进行原子读/写?
(可以通过返回原子加 0 的结果来模拟原子读取,但是没有等效的原子写入。)
最佳答案
我觉得你们混在一起了atomic memory access与 cache coherence .前者是在软件中构建同步原语(自旋锁、信号量和互斥量)所需的硬件支持,而后者是对工作在同一总线上的多个芯片(多个 CPU 和外围设备)的硬件支持,并且具有主内存的一致 View 。
不同的编译器/库为第一个提供不同的实用程序。例如,这里是 GCC intrinsics for atomic memory access .它们都归结为生成 compare-and-swap或 load-linked/store-conditional基于指令 block 取决于平台支持。编译您的源代码,例如,为 GCC 使用 -S
并查看生成的汇编器。
您不必为缓存一致性明确地做任何事情——它都在硬件中处理——但它肯定有助于理解它是如何工作的,以避免像 cache line ping-pong 这样的事情发生。 .
有了这一切, aligned 单个单词的读取和写入在所有商品平台上都是原子的(如果我在这里错了,请有人纠正我)。由于 int
的大小小于或等于处理器字,因此您已被覆盖(请参阅上面的 GCC 内置链接)。
重要的是读写的顺序。这就是架构内存模型很重要的地方。它规定了硬件可以和不能对哪些操作进行重新排序。示例是更新链表——在项目本身处于一致状态之前,您不希望其他 CPU 看到链接的新项目。明确 memory barriers (通常也称为“内存栅栏”)可能是必需的。 Acquire 屏障确保后续操作不会在屏障之前重新排序(假设您在项目内容之前读取链表项目指针),Release 屏障确保之前的操作在屏障之后不会重新排序(您在写入新链接指针之前写入项目内容)。
volatile
经常被误解为与上述所有内容相关。事实上,它只是告诉编译器不要在寄存器中缓存变量值,而是在每次访问时从内存中读取它。许多人认为它是 "almost useless"用于并发编程。
很抱歉回复冗长。希望这会稍微清除它。
编辑:
即将推出的 C++0x 标准最终解决了并发问题,请参阅 Hans Boehm's C++ memory model papers了解更多详情。
关于windows - BSD 以外的操作系统的原子加载/存储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3223602/