欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 【c++】内存序 和 内存一致性模型

【c++】内存序 和 内存一致性模型

2025/3/19 11:48:09 来源:https://blog.csdn.net/weixin_43233774/article/details/146353580  浏览:    关键词:【c++】内存序 和 内存一致性模型

c++ 11 中为了支持并发,定义了内存序和内存一致性模型。这个概念听起来非常高深,好像是在多线程编程领域浸淫多年之后的神级程序员才能搞明白,并用明白的东西。

本文尝试用最简单的方式说清楚这个概念。因为这个概念真的超级简单,大家真的被这个概念欺骗了。

我用一句话就能说清楚。内存一致性模型的本质是防止 编译器和CPU过度优化。意思是告诉 编译器和 CPU 在什么情况下,不要做乱序处理。

编译器和CPU优化

举个例子:

std::atomic<bool> valVailable(false); 
auto imptValue = computeImportantValue();   //计算值
valAvailable = true;                        //告诉另一个任务,值可用了

假设线程 A 在执行上面的代码,线程B 在轮询变量 valAvailable。当 valAvailable 变为 true 时,使用 imptValue 变量做自己的事情。

这种情况下,imptValue 变量在 valAvailable 之前被赋值就很重要了。从代码上看,这不是明摆着么?

但事实上,如果 valAvailable 不是原子变量,所有编译器看到的是给相互独立的变量的一对赋值操作。通常来说,编译器会被允许重排这对没有关联的操作。变成

valAvailable = true;                        //告诉另一个任务,值可用了
auto imptValue = computeImportantValue();   //计算值

最终造成错误。
即使编译器没有重排顺序,底层硬件也可能重排(乱序执行)(或者可能使它看起来运行在其他核心上),因为有时这样代码执行更快。

原子变量与内存序

内存序往往和原子变量一起使用。普通变量意味着内存序不重要。因此把普通变量用在并发场景是绝对的错误。

上面的代码成立还有一个保证,就是c++对原子变量的默认内存序要求是:std::memory_order_seq_cst,意味着 全局顺序一致性。在本次操作之前的所有读写操作,不允许重排到后面,后面所有的读写也不允许重排在我前面。

此外,c++ 还有另外 5 种内存序

  • std::memory_order_acq_rel:同时具有 acquire 和 release 语义
    对于当前操作:

    • 读操作:具有 acquire 语义,确保后续操作不会重排到它之前。

    • 写操作:具有 release 语义,确保前面的操作不会重排到它之后。

  • std::memory_order_release:禁止前面写操作重排到它之后,确保本线程的修改对其他线程的获取操作可见。

  • std::memory_order_acquire:禁止后续读操作重排到它之前,确保能观察到其他线程的释放操作。

  • std::memory_order_consume:保证数据依赖顺序(已不推荐使用)。

  • std::memory_order_relaxed:仅保证原子性,无顺序约束,就是说编译器和 cpu 可以随便重排,只要保证本次操作是原子的就行。

具体该怎么用,我就不讲了。知道概念就行

  1. 内存序是为了防止编译器和cpu乱序执行
  2. 内存序只结合原子变量在多线程编程下使用,普通变量没必要整这个概念。
  3. c++ atomic 变量 默认内存序设置 是禁止原子操作前后的一切重排序的,所以不懂内存序也可以随便用 atomic 而不出错。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词