C++的内存序(memory order)是什么_C++多线程内存模型与同步顺序讲解

大家好,这是我的一位老朋友,谈到 C++ 内存排序时。
记得第一次接触这个东西的时候确实让我很头疼,但是随着时间的推移,我也开始慢慢理解了。

首先我们要讲一下内存对齐的关键作用。
为了提高性能,现代 CPU 会秘密地重新排序自己的指令。
这在单线程环境中可能不是问题,但在多线程环境中,可能会导致数据不一致或逻辑错误。
记忆的顺序就像交警。
这告诉编译器和 CPU 哪些任务不能随意重新排序,从而确保跨线程的任务的排序和可见性。

然后我们就来说说六种内存对齐策略。
这六种策略从最弱到最强分别是缓解、消耗、获取、释放、acq_rel 和 seq_cst。
例如,如果您只想更新计数器,那么放松就足够了,因为它只保证原子性,而不保证同步或排序。
但是,如果您操作共享数据,则可能需要使用 Acquire 或 Release 来确保数据可见性。

说到这里,我们应该提到释放-获取配对。
它就像一对双胞胎一起工作,建立线程之间的同步关系。
例如,线程1 在写入数据后使用Release,线程2 在读取数据前使用Acquire,以保证数据的一致性。

我们来谈谈内存模型和性能之间的权衡。
C++ 支持三种内存模型:顺序、获取-释放和宽松。
顺序一致模型是最安全的,但性能最低。
宽松的模型具有最高的性能,但开发人员必须确保准确性。

最后,选择内存顺序的原则也很重要。
首先,我们需要保证准确性。
如有疑问,请使用最强的 seq_cst,然后根据需要进行调整。
此外,避免过度约束并使用最弱的内存排序来满足您的要求。

简单来说,内存排序是多线程编程中非常重要的工具。
使用得当,不仅可以保证程序的准确性,还可以优化性能。
不过这个其实学起来有点复杂,需要更多的练习和总结。

多线程实现的四种方式

1 . 线程为空
结果:速度快,适合简单的情况,但由于行数过多,容易出现内存和调度问题。

案例:Android早期使用Thread来实现UI功能,但后来由于线程泄漏而放弃了它。

否:创建线程大约需要1 -1 0ms(取决于系统资源)。

警告:除非工作量很小且没有并发冲突,否则不要这样做。

2 人事服务
结果:适合线程池和任务队列的精确控制。

案例:Spring Boot通常使用ThreadPoolExecutor(如newFixedThreadPool(1 0))来限制核心线程数量; )
否:ThreadPoolExecutor可以配置队列大小(如Integer.MAX_VALUE,但会占满内存)。

警告:首先使用ThreadPoolExecutor;不要对线程数进行硬编码。

3 ForkJoin框架
结果:并行流+lambda简化并发;但是,它依赖于 JVM 调度。

案例:Java 8 处理1 M元素排序; commonPool 自动进行负载平衡。

Number:默认使用默认的CPU核心数(如8 核)。

注意:不要盲目使用并行流;首先测试是否可以识别数据源。

4 演员模型(例如 Akka)
结果:通过消息传递孤立但回避全球局势。

事件:Akka Actor 创建一系列调用,如 Props().create(WorkerActor)。

数字:Akka actor 创建成本为 1 -2 μs(跨帧)。

警告:在使用actor之前,首先验证该任务是否适合消息同步。

零基础入门超线程技术

今天早上我在调试一个多线程程序,突然死机了。
屏幕上出现“流被阻止”的消息。
我检查了任务管理器,发现另一个线程占用了所有CPU资源。
直到那时我才意识到,如果多线程管理不当,实际上会减慢整个系统的速度。
顺便翻开了一本关于超线程技术的书,里面提到了CGMT、FGMT和SMT三类,让我对多线程有了新的认识。

CGMT,粗多线程,就像两个工人交替工作。
例如,一名工人处理零件,另一名工人检查质量,这样就没有人闲着。
在CPU中,当一个线程由于缓存未命中而停止时,另一个线程可以接管,避免浪费CPU资源。
我记得书上说这个技术对于使用ICache和DCache来说非常重要。
如果缓存设计得不是很好,比如无法实现“全局线程miss on miss”,那么CGMT的效果就会大打折扣。

FGMT,细粒度多线程,每个时钟周期进行切换。
这是工人在加工零件时检查质量的方法。
虽然有效,但要求也很高。
书上说FGMT要求活动线程的数量大于管道阶段的数量,否则会发生停顿。
而且,FGMT对编译器提出了很高的要求,要求消除指令之间的数据依赖关系,否则编译器会出错。
我只是想,如果编译器不能处理这些依赖关系,那么 FGMT 的好处就会消失。

SMT,同步多线程,与超标量架构相结合,几乎可以与 FGMT 一样高效。
然而,SMT需要处理很多问题,例如缓存争用、分支预测器争用等。
我记得书中提到SMT对延迟不敏感,可以通过牺牲延迟来增加缓存容量。
这让我思考:如果SMT真的可以处理延迟,我们是否可以设计一个更高效的缓存系统?
最后,本书还提到了超线程技术的新应用,例如实例优化、实现拜占庭容错、单线程并行化等。
我对单线程并行化特别感兴趣,因为这意味着即使是单个线程也可以通过 SMT 同时执行繁忙和未使用的分支分支,从而避免在执行分支指令时挂起。
然而,这要求分支预测器非常准确,否则不正确的预测会污染缓存。

总的来说,超线程技术通过CGMT、FGMT和SMT提供多线程能力,优化多线程环境下的性能。
但在实现和优化该技术时需要考虑很多因素,例如硬件设计、编译器支持、缓存管理、分支预测、资源调度和代码优化。
这让我想:如果未来能够开发出更智能的编译器和缓存系统,超线程技术是否会出现更大的突破?