大家好,想请教一个关于 CPU 与内存运行方式的问题

2023-03-29 13:48:50 +08:00
 johnnyleaf

我是一名编程小白,想请教大家

如果 CPU cache 通过写广播和事务串行化能保证 cache 中缓存的数据的一致性 那为什么我们在多进程操作类似 int8 类型数据的时候,代码里还要加读写锁? 代码里的读写锁在这里充当了什么角色?

有没有大佬能为我解释一下这个问题?虚心求教

1563 次点击
所在节点    Python
13 条回复
duke807
2023-03-29 14:09:30 +08:00
只有可以原子操作的数据才不用加锁,譬如用 int

int8 在 pc 上好像不能保证原子操作吧

譬如 int8 后面紧贴另一个 int8 ,你修改第一个 int8 的时候是否会影响另一个线程同时访问第二个 int8 ?
duke807
2023-03-29 14:09:52 +08:00
和 cache 没关系
johnnyleaf
2023-03-29 14:11:26 +08:00
@duke807 cpu 缓存不会缓存 int8 吗
duke807
2023-03-29 14:16:46 +08:00
@johnnyleaf
跟缓存没关系,就算有关系也是 cpu 底层实现,用户不用管
你的问题主要涉及到的是 cpu 指令集的原子操作,不同架构的 cpu 有区别
你查关键字:cpu 原子操作
duke807
2023-03-29 14:19:56 +08:00
你可以先看一下不带 cache 的,内存是内部 sram 的 mcu 的原子操作,譬如 cortex-m 的 mcu
sujin190
2023-03-29 14:23:42 +08:00
其实就是不是每个操作都是不开写广播和事务串行化能保证 cache 中缓存的数据的一致性的,只有你在代码里特别指定的时候才开,本来这东西就很耗性能,没必要每个操作都开,而且吧实际情况中单个操作原子性并不能保证整体操作的原子性,很多是个一个具体功能操作是需要很多个原子操作来完成的,而这个具体功能需要整体原子性,这下你懂了吧
johnnyleaf
2023-03-29 14:27:13 +08:00
@duke807 感谢您的指教🤝,我去好好研究一下
johnnyleaf
2023-03-29 14:28:45 +08:00
@sujin190 单个操作的原子性并不能保证整体操作的原子性。我再去学学吧,我还是知识掌握的太少。
churchmice
2023-03-29 14:29:54 +08:00
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
}
}
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
johnnyleaf
2023-03-29 14:49:31 +08:00
@churchmice 我下去了解一下 resource sharing ,您说的我大概懂了🤝
johnnyleaf
2023-03-29 14:50:49 +08:00
@oldshensheep 我仔细看了一下你提供的两个链接,🤝,我需要去掌握更多的知识。
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 能绕过这些优化,确保数据的全局可见。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/928136

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX