嗯,concurrent queue 是这样的。这两天在网上也看了一些资料,大概明白一些。
这个问题有两个方面,编译器的指令重排,和 cpu 体系结构上的保证。编译器层面,store 保证在此之前的 write 不会移到 store 后面。load 保证后面的 read 不会移到 load 前面。
在体系结构上,
(1) 所有的 write 会先进入本地的 store buffer。store buffer 会异步的方式写入内存,但是本地 core 在读 cache 时会搜索 store buffer。所以本地看到的永远是最新值。
(2) std::atomic 里的 store 命令把 store buffer 里的内容写到内存,同时通知所有 core,把其他 core 上对应 cache 做 invalidate。这个结构叫 invalidation queue。Invalidation queue 也是异步的方式更新本地 cache。core 在读 cache 时不会搜索 invalidation queue。所以如果不做特殊处理,其他 core 上看到的变量有可能落后。
(3) std::atomic 里 load 的作用就是主动应用 invalidation queue。之后就只能从内存里读,也就读到了 store 之后的最新值。
因为 store buffer 和 invalidation queue 是一体更新的,所以在 store 命令之前更新的变量,也必然出现在 store buffer 中并被写入了内存。换句话说,
x=1;
y=2;
z.store(3);
虽然只有 z 用了 store,但对于另一个线程里 z.load() 之后所有的命令都能看到最新的 x 和 y。
我之前糊涂的地方,在于没意识到 store buffer 是整体作用的。x, y 必然先进 store buffer。不存在只把 z 写回内存 (因为用了 store),而把 x, y 漏掉的情况。
【 在 lllho 的大作中提到: 】
: 你用的库应该至少有配置对入队时做写屏障,出队时做读屏障
--
修改:Maksim FROM 45.56.153.*
FROM 45.56.153.*