|
导读:
本文第一目的是对自己知识的印证以及相关概念的理解,所以不会从头开始讲相关的知识,为顺畅阅读本文,需要读者有以下知识背景或者术语:
1.cache
2.cache coherence
3.Store Buffer
4.Invalid Queue
5. MESI,MOESI,MESIF等
6. memory consistency
7. SC,TSO,XC等内存一致性模型(memory consistency model)
8.内存屏障
9.C++11 基本语法
10. HLL原子操作(本文主要讲C++)
11.硬件内存一致性模型 与 HLL内存一致性模型
12.c++11标准里不同的memory order
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
} memory_order;
本文实验环境为: Windows 7 + vs2013 32位编译 ,程序运行CPU为 i7-4790
本文例子:
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x()
{
x.store(true,std::memory_order_release); // 1
}
void write_y()
{
y.store(true,std::memory_order_release); // 2
}
void read_x_then_y()
{
while(!x.load(std::memory_order_acquire)); // 3
if(y.load(std::memory_order_acquire)) // 4
++z;
}
void read_y_then_x()
{
while(!y.load(std::memory_order_acquire)); // 5
if(x.load(std::memory_order_acquire)) // 6
++z;
}
int main()
{
x=false;
y=false;
z=0;
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
assert(z.load()!=0); // 7
}代码源自C++ Concurrency In Action 2rd 第5章
上述实例代码中,虽然使用了acquire/release语义,但仍然可能触发assert。
由于write_x和write_y是在不同的线程,所以x,y变量之间的store操作没有order限制,这会导致出现如下可能
1. 线程c看见x为true, y仍然为false
2. 线程d看见y为true,x仍然为false
故会导致z为0,触发assert。
原文在下面的卡片里面,有兴趣的话可以读一读。
然而问题来了:在 C++ SC FOR DRF 的内存模型下,只要加了内存屏障,无论z的值无论如何也不可能为0!
我在网上找了很多资料,都没有说明为什么z可能为0,最多只是笼统的说是C++11规范里面这么写的,至于底层逻辑,则并没有说。经过了很久的煎熬,于是我有了个猜测:在X86 TSO的内存一致性模型下,其实编译器并没有真正加内存屏障,于是我决定实际的跑一下代码,看看CPU到底做了什么:

store x 的反汇编,并没有加入任何内存屏障以及lock指令

load x 以及load y 的反汇编,同样没有加入任何内存屏障以及lock指令
看完汇编代码,果然验证了我的猜测,若没有加入内存屏障的情况下,确实有出现z == 0情况,具体情况在 X86 TSO 内存一致性模型下,我只分析一种情况来抛砖引玉:
首先上 TSO CPU模型图(借用 @王大龙 的图):

TSO CPU模型图
在这种硬件内存一致性模型下 其中一种可能的执行时序为:

thread a,c run in core 0;thread b,d run in core 1;
参考文献以及博客:
《A Primer on Memory Consistency and Cache Coherence》
lychee:C++并发编程:Acquire和Release语义
好好说说c++内存序--以单例模式为例子
CPU缓存一致性协议—MESI详解
内存屏障今生之Store Buffer, Invalid Queue
林夕:【译文】硬件内存模型 |
|