C++内存模型和char数组上的竞争条件
C++内存模型和char数组的竞争条件问题
在C++11中,支持C++11的平台必须能够在不发明写入的情况下访问大小为一个char的存储空间。x86确实具备这种能力。如果处理器必须在任何时候修改32位,那么它必须具备一个32位宽的char。
(一些背景推理:数组是连续存储的,而char没有填充(3.9.1)。)
至少只要他能够考虑到足够多的其他平台...而像他这样的人肯定能够做到这一点 🙂
说句题外话,Herb Sutter在《原子武器》演讲中非常明确地指出了这一点。
此外,我认为重点是天真的实现会发明虚假的写入。但这并不意味着体系结构不会同时支持一种更昂贵、正确的操作。在单线程模式下,你不会希望支付这样的代价。
关于单线程模式...据我所知,编译器无法知道是否是单线程的,Hans明确提到,他们通过禁止某些东西(如推测性写入)失去了一些性能。
Ram-bus的工作方式和CPU的逻辑工作方式是有区别的。Stroustrup知道这一点(并且期望读者了解这一点)。x86汇编器可以轻松访问字节。但是Ram接口会读取和写入整个32(或64)位的字。
C++内存模型和字符数组上的竞争条件问题
在Bjarne的观点中,他认为现代大多数处理器是可以在写入一个字节之前不需要先读取整个字的,或者至少可以表现得好像是这样。特别是,如果有一个char数组[2],线程一只访问array[0],线程二只访问array[1](包括两个线程同时修改值的情况),那么你不需要额外的同步,这是由标准保证的。如果硬件不直接支持这一点,编译器将不得不自行添加同步机制。
需要注意的是上面提到的"as if"。现代硬件确实按照缓存行而不是字节访问主存。但它也有办法在缓存行中修改单个字节,这样在写回时,处理器核心将不会修改在其缓存中没有被修改的字节。
解决方法:
- 确保线程一只访问array[0],线程二只访问array[1],这样就不需要额外的同步。
- 如果硬件不支持直接修改单个字节,编译器会自动添加同步机制。
- 注意"as if"的概念,即使现代硬件按照缓存行访问主存,也可以修改单个字节。