【问题标题】:C++ memory model and race conditions on char arrayschar 数组上的 C++ 内存模型和竞争条件
【发布时间】:2013-11-23 01:50:32
【问题描述】:

基本上我很难理解这一点:(来自 Bjarne 常见问题解答)

但是,大多数现代处理器无法读取或写入单个 字符,它必须读或写一个完整的单词,所以赋值给 c 真的是``读取包含c的单词,替换c部分,然后写 再次返回这个词。'' 由于对 b 的赋值是相似的,所以有 两个线程甚至有很多机会相互破坏 尽管线程不(根据其源文本)共享数据!

那么如果元素之间没有 3(7?) 个字节填充,char 数组如何存在呢?

【问题讨论】:

  • 关于本段的另一个问题,关于它对“现代硬件”的主张:Can modern x86 hardware not store a single byte to memory?。 (TL:DR:无论硬件在内部做什么,所有具有字节存储指令的 ISA 都不会对周围字节产生任何架构上可见的影响,因此不存在软件正确性问题。早期的 Alpha AXP 是唯一没有字节加载/存储指令,这是 C++11 内存模型的问题。)

标签: c++ c++11 race-condition memory-model


【解决方案1】:

我认为 Bjarne 在这方面是错误的,或者至少,他是 大大简化了事情。大多数现代处理器 无需先读取一个完整的字就可以写入一个字节, 或者更确切地说,他们表现得“好像”就是这种情况。在 特别是,如果你有一个char array[2];,并且只有一个线程 访问array[0],线程二只访问array[1] (包括当两个线程都在改变值时),那么你 不需要任何额外的同步;这是有保证的 按标准。如果硬件不允许直接这样做, 编译器必须自己添加同步。

注意上面的“好像”非常重要。现代硬件 确实通过高速缓存行访问主内存,而不是字节。但它也 具有修改高速缓存行中单个字节的规定,因此 回写时,处理器内核不会修改字节 在其缓存中未修改的。

【讨论】:

    【解决方案2】:

    支持 C++11 的平台必须能够访问大小为 1char 的存储,而无需发明写入。 x86 确实有这种能力。如果一个处理器必须在任何时候一次修改 32 位,它必须有一个 32 位宽的char

    (一些背景推理:数组是连续存储的,字符没有填充(3.9.1)。)

    【讨论】:

    • @NoSenseEtAl:只要他能想到足够多的其他平台......他描述的一个角色肯定是:-)
    • @NoSenseEtAl:不管怎样,Herb Sutter 在Atomic Weapons 会谈中非常清楚地表明了这一点。
    • @NoSenseEtAl:另外,我认为关键是 naive 实现 read-modify-write 发明了虚假写入。但这并不是说该架构不支持更昂贵、更正确的操作。在单线程模式下,你不会愿意付出这样的代价。
    • 关于单线程模式... afaik 编译器无法知道它是否是单线程的,Hans 明确提到他们通过禁止投机写入等某些东西而损失了一些性能
    • @NoSenseEtAl Ram 总线的作用与 CPU 的逻辑工作之间存在差异。 Stroustrup 知道这一点(并期待他的读者提供这些知识)。 x86-Assembler 可以轻松访问字节。但 Ram-Interface 会读写整个 32(或 64)位字。
    猜你喜欢
    • 2018-11-08
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    相关资源
    最近更新 更多