IE盒子

搜索
查看: 99|回复: 1

也说内存序,解析《C++ Concurrency IN ACTION 》中的 ...

[复制链接]

2

主题

5

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2022-9-22 16:49:54 | 显示全部楼层 |阅读模式
导读:

本文第一目的是对自己知识的印证以及相关概念的理解,所以不会从头开始讲相关的知识,为顺畅阅读本文,需要读者有以下知识背景或者术语:
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
林夕:【译文】硬件内存模型
回复

使用道具 举报

2

主题

7

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 7 天前 | 显示全部楼层
啊啊啊啊啊啊啊啊啊啊啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表