对象的创建过程是安全的吗
- 重排序问题
- 编译器优化(指令重排序)
- CPU指令级并行重排序(指令重排序)
- 内存重排序
- 原子性与内存序
- 对象的创建(new)
- 对象的创建过程
- 对象的创建过程是线程安全的吗?
- new运算符创建对象不是原子操作
重排序问题
- 重排序问题分为两种:指令重排序和内存重排序
- 指令重排序:是CPU为了提高指令执行效率而采用的一种技术,允许编译器和处理器在不改变程序执行结果的前提下,对指令的执行顺序进行调整(即CPU不一定会严格按照程序中指令的顺序来执行),以充分利用CPU的并发执行能力,提高指令执行效率和性能
- 指令重排序可以提高程序的执行效率,但也可能引入多线程程序中的内存可见性问题和竞态条件。因此,在多线程编程中,需要特别注意指令重排序的影响,并采取相应的同步措施来确保程序中的内存可见性和一致性
- 编译器和处理器在进行指令重排序时,会遵守数据依赖性原则和内存模型规则,存在数据依赖关系的指令不会被重排序,以确保程序的执行结果不变,因为这种重排序会改变程序的执行结果
- 内存重排序:是编译器在执行程序时,为了提高内存的访问效率,可能会内存的读写进行缓存和重新排序。然后这种重排序可能会在多线程的情况下产生异常情况
- C++11及更高版本引入了std::atomic和内存顺序的概念,以更精细地控制多线程程序中的内存可见性和一致性。通过使用std::atomic和指定内存顺序,程序员可以明确禁止某些类型的指令重排序,从而避免潜在的并发问题
编译器优化(指令重排序)
- 编译器优化:在不改变单线程程序语义的前提下,编译器会根据指令的依赖关系、CPU的架构等因素,在不改变代码功能的前提下,对代码的结构和顺序进行修改和调整(内联函数、循环展开、尾递归消除、公共子表达式消除、数据对齐与预取等),以便生成更高效的CPU指令
- 编译器优化不仅能让程序运行得更快,还能减少内存的使用、缩小二进制文件的大小。但也可能导致代码体积增大、编译时间延长,甚至在某些情况(如:多线程)引入异常
-
单线程环境中,这种优化通常是安全的,因为指令的执行顺序不会改变程序的结果
-
多线程环境中,如果两个线程同时访问或修改同一个对象,并且这些访问或修改之间没有适当的同步,那么编译器优化可能会导致竞态条件和其他未定义行为
-
C++入门系列第二十一讲:编译器优化——让你的程序飞起来!
-
深入理解编译器:优化程序性能的关键
CPU指令级并行重排序(指令重排序)
- CPU指令: 是中央处理器能够识别