• C++ 20 内存模型(一)


    C++ 20 内存模型(一)

    多线程的基础是优秀的内存模型

    C++20 内存模型:

    • 高复杂性, 难以理解
    • 对多线程有更深入的理解

    内存布局

    位域

    member_name成员名, width bit 宽度

    struct bit_field_name
    {
        type member_name : width;
    };
    
    • 1
    • 2
    • 3
    • 4
    struct my_struct
    {
    	char a;
    	int b : 5; // 最大存储 2^5 ,只使用低五位节约空间...
    	int c : 11,
    		: 0,
    		d : 8;
    	int e;
    	double f;
    	string g;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    位域的对齐

    不允许跨越 uint 大小的区域

    struct my_struct2
    {
    	char a;
    	int c : 30;
    	int b : 5;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    c: 30 bit + 空2 bit + b 5 bit

    例子:

    #include 
    #include 
    using namespace std;
    
    struct my_struct
    {
    	char a;
    	int b : 5;
    	int c : 11,
    		: 0,
    		d : 8;
    	int e;
    	double f;
    	string g;
    };
    
    
    int main(int argc, char* argv[])
    {
    	my_struct s{
    		.a = 'a',
    		.b = 1,
    		.c = 2,
    		.d = 3,
    		.e = 4,
    		.f = 5.0,
    		.g = "hello"
    	};
    	cout << &s << endl;
    	cout << "sizeof(my_struct) = " << sizeof(my_struct) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    使用内存查看工具查看内存

    **这种方式可以解决内存伪共享问题: **

    来举一个java多线程的例子

    class MyObject
    {
    private long a;
    private long b;
    private long c;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    按照Java规范,MyObject的对象是在堆内存上分配空间存储的,而且a、b、c三个属性在内存空间上是近邻,如下所示。

    a(8个字节) b(8个字节) c(8个字节)

    我们知道,X86的CPU中Cache Line的长度为64字节,这也就意味着MyObject的3个属性(长度之和为24字节)是完全可能加载在一个Cache Line里的。如此一来,如果我们有两个不同的线程(分别运行在两个CPU上)分别同时独立修改a与b这两个属性,那么这两个CPU上的Cache Line可能出现如下所示的情况,即a与b这两个变量被放入同一个Cache Line里,并且被两个不同的CPU共享。
    img

    根据MESI协议的相关知识,我们知道,如果Thread 0要对a变量进行修改,则因为CPU 1上有对应的Cache Line,这会导致CPU 1的Cache Line无效,从而使得Thread 1被迫重新从Memory里获取b的内容(b并没有被其他CPU改变,这样做是因为b与a在一个Cache Line里)。同样,如果Thread 1要对b变量进行修改,则同样导致Thread 0的Cache Line失效,不得不重新从Memory里加载a。如此一来,本来是逻辑上无关的两个线程,完全可以在两个不同的CPU上同时执行,但阴差阳错地共享了同一个Cache Line并相互抢占资源,导致并行成为串行,大大降低了系统的并发性,这就是所谓的Cache伪共享。

  • 相关阅读:
    【网络安全】面试中常见问题--sql注入篇
    C++怎么读取XML文件?
    shell脚本的系统性学习笔记
    Flask学习笔记
    【LeetCode刷题(数据结构与算法)】:平衡二叉树
    不同的方式检查Null
    java计算机毕业设计养生药膳推荐系统源程序+mysql+系统+lw文档+远程调试
    后端搜索条件
    Java架构师主流架构设计模式
    【附源码】计算机毕业设计SSM网上花店销售系统
  • 原文地址:https://blog.csdn.net/qq_42896106/article/details/126195425