【 在 Maksim (Marksim) 的大作中提到: 】
: 标 题: Re: struct 内成员变量多线程可见性的问题
: 发信站: 水木社区 (Thu Mar 25 23:11:58 2021), 站内
:
: 嗯,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 漏掉的情况。
:
你仍然没有搞清楚
从store buffer出去之后进的是cache,离内存还远着呢
根据ISA定义和具体的实现,完全可能z进了内存,xy还在cache里,或者其他cpu看见新的z,但是看见旧的xy
这种情况在x86上不可能,但是在arm上完全可能,所以需要写z之前加上write barrier, 另一个线程读z之后加read barrier
: 【 在 lllho 的大作中提到: 】
: : 你用的库应该至少有配置对入队时做写屏障,出队时做读屏障
:
: --
: ※ 修改:·Maksim 于 Mar 25 23:12:52 2021 修改本文·[FROM: 45.56.153.*]
: ※ 来源:·水木社区
http://www.newsmth.net·[FROM: 45.56.153.*]
--
修改:Maksim FROM 45.56.153.*
FROM 71.198.160.*