V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
johnnyleaf
V2EX  ›  Python

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

  •  
  •   johnnyleaf · 2023-03-29 13:48:50 +08:00 · 1563 次点击
    这是一个创建于 637 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    13 条回复    2023-03-30 02:27:50 +08:00
    duke807
        1
    duke807  
       2023-03-29 14:09:30 +08:00 via Android
    只有可以原子操作的数据才不用加锁,譬如用 int

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

    譬如 int8 后面紧贴另一个 int8 ,你修改第一个 int8 的时候是否会影响另一个线程同时访问第二个 int8 ?
    duke807
        2
    duke807  
       2023-03-29 14:09:52 +08:00 via Android
    和 cache 没关系
    johnnyleaf
        3
    johnnyleaf  
    OP
       2023-03-29 14:11:26 +08:00
    @duke807 cpu 缓存不会缓存 int8 吗
    duke807
        4
    duke807  
       2023-03-29 14:16:46 +08:00 via Android
    @johnnyleaf
    跟缓存没关系,就算有关系也是 cpu 底层实现,用户不用管
    你的问题主要涉及到的是 cpu 指令集的原子操作,不同架构的 cpu 有区别
    你查关键字:cpu 原子操作
    duke807
        5
    duke807  
       2023-03-29 14:19:56 +08:00 via Android
    你可以先看一下不带 cache 的,内存是内部 sram 的 mcu 的原子操作,譬如 cortex-m 的 mcu
    sujin190
        6
    sujin190  
       2023-03-29 14:23:42 +08:00
    其实就是不是每个操作都是不开写广播和事务串行化能保证 cache 中缓存的数据的一致性的,只有你在代码里特别指定的时候才开,本来这东西就很耗性能,没必要每个操作都开,而且吧实际情况中单个操作原子性并不能保证整体操作的原子性,很多是个一个具体功能操作是需要很多个原子操作来完成的,而这个具体功能需要整体原子性,这下你懂了吧
    johnnyleaf
        7
    johnnyleaf  
    OP
       2023-03-29 14:27:13 +08:00
    @duke807 感谢您的指教🤝,我去好好研究一下
    johnnyleaf
        8
    johnnyleaf  
    OP
       2023-03-29 14:28:45 +08:00
    @sujin190 单个操作的原子性并不能保证整体操作的原子性。我再去学学吧,我还是知识掌握的太少。
    churchmice
        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
    }
    }
    oldshensheep
        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
    johnnyleaf
        11
    johnnyleaf  
    OP
       2023-03-29 14:49:31 +08:00
    @churchmice 我下去了解一下 resource sharing ,您说的我大概懂了🤝
    johnnyleaf
        12
    johnnyleaf  
    OP
       2023-03-29 14:50:49 +08:00
    @oldshensheep 我仔细看了一下你提供的两个链接,🤝,我需要去掌握更多的知识。
    secondwtq
        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 能绕过这些优化,确保数据的全局可见。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1078 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:06 · PVG 03:06 · LAX 11:06 · JFK 14:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.