11.内存可见行问题
// ----------------------|----------------------|
// 线程 A | 线程 B |
// | |
// |---------| | |---------| |
// | 控制器 | | | 控制器 | |
// |---------| | |---------| |
// | 运算器 | | | 运算器 | |
// |---------| | |---------| |
// | L1 Cache| | | L1 Cache| |
// |---------| | |---------| |
// ---------------------------------------------|
// L2 Cache |
// ---------------------------------------------|
// 主内存 |
// |---------| |---------| |
// | 共享变量1| | 共享变量2 | |
// |---------| |---------| |
// ---------------------------------------------|
假如线程 A 和线程 B 同时处理一个共享变量,使用图所示 CPU 架构,
假设线程 A 和线程 B 使用不同 CPU 执行,并且当前两级 Cache 都为空, 那么这时候由于 Cache 的存在,将会导致内存不可见问题, 具体看下面的分析。
- 线程 A 首先获取共享变量 X 的值,由于两级 Cache 都没有命中 ,所以加载主内存中 X 的值,假如为 0。
然后把 X=O 的值缓存到两级缓存, 线程 A 修改 X 的值为 1, 然后将其写入两级 Cache, 并且刷新到主内存。
线程 A 操作完毕后,线程 A 所在的 CPU 的两级 Cache 内和主内存里面的 X 的值都是 1。 - 线程 B 获取 X 的值,首先一级缓存没有命中,然后看二级缓存,二级缓存命中了 , 所以返回 X= 1 。
到这里一切都是正常的, 因为这时候主 内存中也是 X=1 。然后线 程 B 修改 X 的值为 2,
并将其存放到线程 2 所在的一级 Cache 和共享二级 Cache 中,最后更新主内存中 X 的值为 2,到这里一切都是好的。 - 线程 A 这次又需要修改 X 的值, 获取时一级缓存命中, 并且 X=1,到这里问题就出现了,明明线程 B 已经把 X 的值修改为了 2,
为何线程 A 获取的还是 1 呢?这就是共享变量的内存不可见问题, 也就是线程 B 写入的值对线程 A 不可见