C++ C++;11内存模型防止内存撕裂和冲突?

C++ C++;11内存模型防止内存撕裂和冲突?,c++,multithreading,thread-safety,c++11,C++,Multithreading,Thread Safety,C++11,阅读C++11草案时,我对第1.7.3条很感兴趣: 内存位置要么是标量类型的对象,要么是具有非零宽度的相邻位字段的最大序列。。。两个执行线程(1.10)可以在不相互干扰的情况下更新和访问单独的内存位置 本条款是否保护不受硬件相关竞态条件的影响,例如: 在两个总线事务中更新内存的未对齐数据访问(内存撕裂) 如果系统内存单元中有不同的对象,例如,一个32位字中有两个16位有符号整数,并且单独对象的每次独立更新都需要写入整个内存单元(内存冲突) 它不能防止内存撕裂,只有当两个线程访问同一内存位置时,

阅读C++11草案时,我对第1.7.3条很感兴趣:

内存位置要么是标量类型的对象,要么是具有非零宽度的相邻位字段的最大序列。。。两个执行线程(1.10)可以在不相互干扰的情况下更新和访问单独的内存位置

本条款是否保护不受硬件相关竞态条件的影响,例如:

  • 在两个总线事务中更新内存的未对齐数据访问(内存撕裂)
  • 如果系统内存单元中有不同的对象,例如,一个32位字中有两个16位有符号整数,并且单独对象的每次独立更新都需要写入整个内存单元(内存冲突)

它不能防止内存撕裂,只有当两个线程访问同一内存位置时,内存撕裂才可见(但该条款仅适用于单独的内存位置)


根据您的示例,它似乎可以防止内存冲突。实现这一点的最有可能的方法是,一个不能同时写入少于32位的系统将具有32位的
char
,然后两个单独的对象永远不能共享一个“系统内存单元”。(在具有32位字符的系统上,两个16位整数可以相邻的唯一方法是作为位字段。)

关于第二点,标准保证不会有竞争。也就是说,我被告知这种保证并没有在当前的编译器中实现,甚至可能无法在某些体系结构中实现

关于第一点,如果第二点是有保证的,并且如果您的程序不包含任何竞赛条件,那么自然的结果是这也不会是竞赛条件。也就是说,假设标准保证写入不同子字位置的操作是安全的,那么唯一可能存在争用条件的情况是多个线程访问同一个变量(在字之间拆分,或者更可能是在缓存线之间拆分)


同样,这可能很难甚至不可能实现。如果未对齐的数据穿过缓存线,则几乎不可能保证代码的正确性,而不会对性能造成巨大损失。出于这个和其他原因,您应该尽量避免未对齐的变量(包括原始性能,对接触两条缓存线的对象的写入涉及将多达32个字节写入内存,如果任何其他线程接触任何缓存线,还涉及缓存同步的成本…

可能重复@HansPassant:从我的快速阅读来看,这个问题似乎与visibi更相关由于线程之间共享对象的不确定性,我在这里询问更新不同对象导致的内存冲突。对于多线程而言,问题稍微复杂一些,而不仅仅是8/32字节。一级缓存的实际写操作是以缓存线大小粒度完成的。当前编译器的写操作通常不能小于X(16字节是intel的常用数字)块中的字节。另一方面,处理器使用其他技术来保证(或尝试保证)这不是一个问题,例如,将缓存线标记为脏的,并强制其他处理器在写入缓存线之前重新加载,或更复杂的同步算法。@dribeas:在ISA级别,可以更新较小的区域。处理器必须采用总线锁,或使用缓存一致性算法来实现这一点是一种实现详细信息。重要的是ISA为较小区域的原子更新提供了原语,而无需软件互斥。是……和否。未对齐访问的问题不是来自处理器到缓存的写入大小,而是写入可能实际上跨越缓存边界。在写入si时ngle缓存线由缓存一致性算法处理,我不确定这些算法能否处理对不同缓存线写入的模拟原子性(即,硬件必须锁定两条缓存线,写入和释放;或者同时将两条缓存线标记为脏线,或者……无论算法做什么,但同时在两条缓存线上)@dribeas:已经同意不会阻止撕裂。提供的是更新不会更改不属于对象的字节(撤消另一个线程所做的更改)。对两个缓存线进行的两个非事务性但单独的原子更新提供了这一点。