之前我写代码同步多线程访问时,基础数据类型都加的有 atomic 关键字,后来领导看到了说基础数据类型不加也是原子操作。 今天面试时,面试官说基数数据类型访问不是原子的,而且和编译器架构无关。
应该加 atomic 关键字,但在现代 x86 等架构的 cpu 上对 bool ,int 类型的操作是原子的,或者说视同原子的。
1
xtreme1 2023-08-28 18:14:41 +08:00
https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html
8.1.1 Guaranteed Atomic Operations |
2
mtrec 2023-08-28 18:15:13 +08:00
面试官是对的 atomic 之后是原子的 里面还涉及更深一层的 memory order
“在现代 x86 等架构的 cpu 上对 bool ,int 类型的操作是原子的,或者说视同原子的” 不对 在多核多线程情况下 每个核都有自己的独占的寄存器/L1/L2 cache 不能保证原子性 |
3
billlee 2023-08-28 18:18:48 +08:00
是原子的,原子意味着着写一个 memory word 不会出现高位写入完成,而低位没完成写入的情况
|
4
inhzus 2023-08-28 18:33:57 +08:00
不用 atomic 有可见性问题
|
5
ajaxgoldfish 2023-08-28 23:37:52 +08:00 via Android
我记得有本书讲的是和 CPU 的位数有关,还和是否为浮点数有关。其中在某些条件下是原子的,超过限定条件就有可能不是原子的。虽然记得不清楚但是应该能否定面试官说的
|
6
hanguofu 2023-08-29 01:53:02 +08:00 via Android
取决于硬件是否支持?
|
7
shawnsh 2023-08-29 09:02:58 +08:00 via Android
怎么牵扯到编译器的架构了
|
8
CrazyRain0001 OP @shawnsh 写漏了,编译器优化和 cpu 架构
|
9
CrazyRain0001 OP @inhzus 对,这点同意
|
10
CrazyRain0001 OP |
11
CrazyRain0001 OP @mtrec 我看这边祖传代码一直是直接用的,不能保证的话不是很容易崩吗?
|
13
Caturra 2023-08-29 11:31:02 +08:00
你让面试官翻译翻译这段话
8.1.1 Guaranteed Atomic Operations The Intel486 processor (and newer processors since) guarantees that the following basic memory operations will always be carried out atomically: - Reading or writing a byte - Reading or writing a word aligned on a 16-bit boundary - Reading or writing a doubleword aligned on a 32-bit boundary The Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically: - Reading or writing a quadword aligned on a 64-bit boundary - 16-bit accesses to uncached memory locations that fit within a 32-bit data bus The P6 family processors (and newer processors since) guarantee that the following additional memory operation will always be carried out atomically: - Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line |
14
mtrec 2023-08-29 12:14:10 +08:00 via Android
@sghwn2 加了 volatile 也不行 volatile 是提醒编译器别优化 可能别的地方也会改这个变量 每次用到的话从内存里重新取值 但是还是没解决多线程下可能的编译器 CPU 指令重排 memory order 能提供更精细的重排控制
|
15
mtrec 2023-08-29 12:16:21 +08:00 via Android
@CrazyRain0001 我不了解你那边代码的情况无法回答你 建议你可以看看 std atomic 相关的内容 cppcon 有一期就是解释这个原理的
|
16
CrazyRain0001 OP @mtrec
> 是这个吗? https://www.bilibili.com/video/BV1Vx411V7Rd/?p=31 简单看了下,他确实指出了代码里对类似 int i 的基础操作是非原子的,包含了不同的 CPU 指令。但看 13 楼引用的这个 intel 开发文档也确实说明了某些 CPU 对于 bool(byte)或者 int(doubleword aligned on a 32-bit boundary)的读写是原子操作 Certain basic memory transactions (such as reading or writing a byte in system memory),所以可以认为这是一个语言层面未作保证只是某些 CPU 支持的特性吗? |
17
mtrec 2023-08-29 18:59:28 +08:00 via Android
@CrazyRain0001 对 是这些视频 这个跟 13 楼讲的不冲突 就用 cppcon 里两个线程跑++i 的例子 CPU 可以保证两次都原子性的从内存读到 i 的值 然后分别一步步写到两个线程各自的 L2/L1 cache 和寄存器里 两个自增也能在 1 tick 完成 原子性的 然后再一步步地 commit 回 L3 再内存 就可能出现覆盖而得不到你想要结果 因为两个线程没有同步机制 而 std atomic 相当于一种硬件同步机制或者硬件锁 底层是通过 CPU 指令来实现的 现在在 ARM 或者 GPU 上支持还不算完善 这些 atomic 操作也是很多 lock free 数据结构的基础
|
18
CrazyRain0001 OP @mtrec #17 好的!感谢回答!
|