我是一名编程小白,想请教大家
如果 CPU cache 通过写广播和事务串行化能保证 cache 中缓存的数据的一致性 那为什么我们在多进程操作类似 int8 类型数据的时候,代码里还要加读写锁? 代码里的读写锁在这里充当了什么角色?
有没有大佬能为我解释一下这个问题?虚心求教
1
duke807 2023-03-29 14:09:30 +08:00 via Android
只有可以原子操作的数据才不用加锁,譬如用 int
int8 在 pc 上好像不能保证原子操作吧 譬如 int8 后面紧贴另一个 int8 ,你修改第一个 int8 的时候是否会影响另一个线程同时访问第二个 int8 ? |
2
duke807 2023-03-29 14:09:52 +08:00 via Android
和 cache 没关系
|
3
johnnyleaf OP @duke807 cpu 缓存不会缓存 int8 吗
|
4
duke807 2023-03-29 14:16:46 +08:00 via Android
|
5
duke807 2023-03-29 14:19:56 +08:00 via Android
你可以先看一下不带 cache 的,内存是内部 sram 的 mcu 的原子操作,譬如 cortex-m 的 mcu
|
6
sujin190 2023-03-29 14:23:42 +08:00
其实就是不是每个操作都是不开写广播和事务串行化能保证 cache 中缓存的数据的一致性的,只有你在代码里特别指定的时候才开,本来这东西就很耗性能,没必要每个操作都开,而且吧实际情况中单个操作原子性并不能保证整体操作的原子性,很多是个一个具体功能操作是需要很多个原子操作来完成的,而这个具体功能需要整体原子性,这下你懂了吧
|
7
johnnyleaf OP @duke807 感谢您的指教🤝,我去好好研究一下
|
8
johnnyleaf OP @sujin190 单个操作的原子性并不能保证整体操作的原子性。我再去学学吧,我还是知识掌握的太少。
|
9
churchmice 2023-03-29 14:29:54 +08:00 1
cache coherency 只是保证你 cache 的内容和 DDR 的内容是一样的
加锁要解决的是 resource sharing,这个跟 cache 一致性关系不大,你即使没有 cache 也得做 比如你现在两个进程都需要通过 uart 打印东西出来,但是系统的 uart 只有一个,你就需要有一个锁去控制当前 uart 能够被谁控制,代码大概如下 while ( 1 ) { if( lock == 0 ) { lock =1 ; uart_print lock = 0; break; } else { sleep 1 } } 如果不加锁,因为进程之前存在切换的问题,有可能两个进程都会读到 lock =0, 然后都认为自己获得了 uart 打印的权限,那 uart 的打印就错乱了 所以你必须使用类似原子操作来干这个事情,原子操作本身就只有一条指令,不存在中间被打断的情况,上面的代码就类似如下,cas 指令的意思就是会去判断 lock 是否等于 0 ,如果相等,则将 lock 设成 1 ,同时将 lock 的原始值 1 返回 while ( 1 ) { if( cas(lock,0,1) == SUCCESS ) { uart_print lock = 0; break; } else { sleep 1 } } |
10
oldshensheep 2023-03-29 14:37:16 +08:00
指令重排
x = y = a = b = 0; Thread A: a = 1; x = b; Thread A: b = 1; y = a; 如果不存在指令重排是不可能出现下列结果的( X86 平台) x == 0 && y == 0 实际上代码可能会这样执行 x = b(0) b = 1 y = a(0) a = 1 见 https://stackoverflow.com/questions/52648800/how-to-demonstrate-java-instruction-reordering-problems 更多例子见 https://www.v2ex.com/t/912912 |
11
johnnyleaf OP @churchmice 我下去了解一下 resource sharing ,您说的我大概懂了🤝
|
12
johnnyleaf OP @oldshensheep 我仔细看了一下你提供的两个链接,🤝,我需要去掌握更多的知识。
|
13
secondwtq 2023-03-30 02:27:50 +08:00
再次推荐 Memory Barriers: a Hardware View for Software Hackers
或者这个:fgiesen.wordpress.com/2014/07/07/cache-coherency Cache coherency primer | The ryg blog 简单来说,如果 CPU 严格按照缓存一致性协议工作,那对于单个指令对单个 cacheline 的操作,是可以保证原子性的。 但是实际实现中,为了性能,CPU 和缓存都不是教条主义,而可能是机会主义。OoO 核心在做 speculative execution 时,简单的算术指令可以直接由 ALU 执行,结果存放在 PRF 中,但是 store 是有副作用的,数据如果真的存进了 L1D ,那就不是 speculative execution 而是生米煮成熟饭了。所以又加了一层缓存 store buffer ,在 retire 之前,store 的结果只放在这个 buffer 里面,并且随时可以撤回,结果在 retire 之后刷进 L1D ,该 buffer 中的内容只对该 buffer 可见。 锁中包含了 memory barrier ,memory barrier 能绕过这些优化,确保数据的全局可见。 |