【C/C++】ARM处理器对齐_伪共享问题

文章目录

    • 1 什么是伪共享?
    • 2 为什么对齐?
    • 3 伪共享的实际影响
    • 4 为什么必须是 64 字节?
    • 5 其他替代方案
    • 6 验证对齐效果
    • 总结

1 什么是伪共享?

伪共享是 多线程编程中的一种性能问题,其本质是:

  • 缓存行(Cache Line):现代 CPU 的缓存以固定大小的块(缓存行)为单位管理数据,常见缓存行大小为 64 字节(如 x86/x64 CPU)。
  • 共享缓存行:如果两个独立的变量(如 _bottom_top)位于同一个缓存行中,即使它们被不同线程访问(如一个线程写 _bottom,另一个线程读 _top),也会导致缓存行被频繁标记为“无效”(Cache Invalidation)。
  • 性能损失:频繁的缓存同步(从 L1/L2 缓存到主存)会显著降低程序性能。

避免伪共享(False Sharing),从而提升多线程程序的性能


2 为什么对齐?

以64字节对齐为例:
通过 alignas(64) 强制变量对齐到 64 字节边界,可以确保:

  • 独占缓存行:每个变量(如 _bottom_top)独占一个完整的缓存行(64 字节),避免与其他变量共享。
  • 隔离修改:当一个线程修改 _bottom 时,不会触发其他线程中 _top 所在缓存行的无效化,反之亦然。

示例内存布局:

// 未对齐时(伪共享)
Cache Line 0: | _bottom (8 bytes) | _top (8 bytes) | ...(剩余 48 字节)|// 对齐到 64 字节后(避免伪共享)
Cache Line 0: | _bottom (8 bytes) | padding (56 bytes)            |
Cache Line 1: | _top (8 bytes)    | padding (56 bytes)            |

32 位 ARM 系统中,为了避免伪共享(False Sharing),通常建议的对齐大小为 32 字节64 字节,具体取决于目标处理器的缓存行(Cache Line)大小。

  1. ARM 系统的缓存行大小
    32 位 ARM 处理器的缓存行大小因架构和型号而异:
  • 较旧 ARMv6/ARMv7 处理器(如 Cortex-A8/A9)通常使用 32 字节 的缓存行。
  • 较新 ARMv7/ARMv8 处理器(如 Cortex-A53/A72)可能采用 64 字节 的缓存行(与 x86/x64 对齐)。

具体需查阅目标 CPU 的文档(如 Technical Reference Manual)确认。

  1. 对齐建议
  • 通用保守方案:32 字节对齐
    若不确定目标处理器的缓存行大小,可保守对齐到 32 字节(覆盖旧型号的 32 字节缓存行):
alignas(32) std::atomic<size_t> _bottom;
alignas(32) std::atomic<size_t> _top;
  • 针对新型号:64 字节对齐
    若目标处理器为较新的 ARMv8 或已知缓存行为 64 字节(如部分 Cortex-A 系列),可直接对齐到 64 字节
alignas(64) std::atomic<size_t> _bottom;
alignas(64) std::atomic<size_t> _top;
  • C++17 自适应方案
    若支持 C++17,使用 std::hardware_destructive_interference_size 自动适配缓存行大小:
#include <new>
alignas(std::hardware_destructive_interference_size) std::atomic<size_t> _bottom;
alignas(std::hardware_destructive_interference_size) std::atomic<size_t> _top;

  1. 验证对齐效果
    通过代码检查变量地址是否为对齐值的整数倍:
#include <iostream>
#include <cstdint>int main() {alignas(32) std::atomic<size_t> _bottom;alignas(32) std::atomic<size_t> _top;// 检查对齐是否成功auto check_alignment = [](const auto& var, size_t alignment) {uintptr_t addr = reinterpret_cast<uintptr_t>(&var);return (addr % alignment == 0) ? "Success" : "Failed";};std::cout << "_bottom 对齐 32: " << check_alignment(_bottom, 32) << "\n";std::cout << "_top 对齐 32: " << check_alignment(_top, 32) << "\n";return 0;
}
  1. 实际性能对比
场景32 字节缓存行(对齐 32)64 字节缓存行(对齐 64)未对齐(伪共享)
线程竞争开销低(若缓存行为 64)高(频繁缓存失效)
内存占用略高(填充空间)更高(填充空间)

  1. 适用场景总结
  • 嵌入式/IoT 设备(旧款 ARMv6/v7):优先对齐 32 字节
  • 高性能 ARM 处理器(如 Cortex-A72):对齐 64 字节
  • 跨平台代码:使用 C++17 的 std::hardware_destructive_interference_size

32 位 ARM 系统中,若无明确缓存行信息,默认对齐到 32 字节是安全选择。
若针对新型处理器或已知缓存行为 64 字节,则对齐到 64 字节。通过合理对齐,可显著减少伪共享带来的性能损失。

3 伪共享的实际影响

假设 _bottom_top 是一个无锁队列的头尾指针:

  • 线程 A 频繁修改 _bottom(入队操作)。
  • 线程 B 频繁修改 _top(出队操作)。
  • 如果它们共享同一个缓存行,每次修改都会导致对方线程的缓存失效,性能可能下降 数倍甚至数十倍

通过对齐到 64 字节,两者的修改完全隔离,避免不必要的缓存同步。


4 为什么必须是 64 字节?

  • 缓存行大小:x86/x64 CPU 的缓存行大小通常为 64 字节,ARM 架构也普遍采用 64 字节。对齐到缓存行大小是最直接的方法。
  • 兼容性:即使某些 CPU 的缓存行更小(如 32 字节),对齐到 64 字节也能覆盖所有常见情况。

5 其他替代方案

  1. 填充字节(Padding)
    手动在变量间插入填充数据,强制隔离:
struct AlignedData {std::atomic<size_t> _bottom;char padding[64 - sizeof(std::atomic<size_t>)];std::atomic<size_t> _top;
};
  • 缺点:需手动计算填充大小,不够灵活。
  1. C++17 std::hardware_destructive_interference_size
    C++17 提供了表示缓存行大小的常量:
#include <new>
alignas(std::hardware_destructive_interference_size) std::atomic<size_t> _bottom;
alignas(std::hardware_destructive_interference_size) std::atomic<size_t> _top;
  • 优点:代码可移植,自动适配不同平台的缓存行大小。
  • 缺点:需要 C++17 支持。

6 验证对齐效果

可以通过以下方式验证变量是否对齐到 64 字节:

#include <iostream>
#include <cstdint>int main() {alignas(64) std::atomic<size_t> _bottom;alignas(64) std::atomic<size_t> _top;// 检查地址是否为 64 的倍数std::cout << "Address of _bottom: " << &_bottom << " (aligned: "<< ((reinterpret_cast<uintptr_t>(&_bottom) % 64 == 0) << ")\n";std::cout << "Address of _top: " << &_top << " (aligned: "<< ((reinterpret_cast<uintptr_t>(&_top) % 64 == 0) << ")\n";return 0;
}

总结

  • 对齐到 64 字节:通过独占缓存行,避免 _bottom_top 之间的伪共享。
  • 适用场景:高频并发访问的原子变量(如无锁数据结构、计数器等)。
  • 推荐方法:优先使用 alignas(64) 或 C++17 的 std::hardware_destructive_interference_size

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka Controller的作用是什么?故障时如何恢复? (管理分区和副本状态;通过ZooKeeper选举新Controller)

Apache Kafka Controller 是 Kafka 集群的核心协调组件&#xff0c;主要承担两大核心职责&#xff1a; 一、核心作用 分区领导者选举 1 // 分区领导者选举逻辑示例&#xff08;伪代码&#xff09; def electLeader(partition: Partition): Unit {val isr partition.inSync…

阿里云前端Nginx部署完,用ip地址访问却总访问不到,为什么?检查安全组是否设置u为Http(80)!

根据你的描述&#xff0c;Ping测试显示数据包无丢失但无法通过公网IP访问服务&#xff0c;说明网络基础层&#xff08;ICMP协议&#xff09;是通畅的&#xff0c;但更高层&#xff08;如TCP/UDP协议或服务配置&#xff09;存在问题。以下是系统性排查与解决方案&#xff1a; 一…

关于STM32 SPI收发数据异常

问题描述&#xff1a; STM32主板做SPI从机&#xff0c;另一块linux主板做主机&#xff0c;通信的时候发现从机可以正确接收到主机数据&#xff0c;但是主机接收从机数据时一直不对&#xff0c;是随机值。 问题原因&#xff1a; 刚发现问题的时候&#xff0c;用逻辑分析仪抓包…

特励达力科LeCroy推出Xena Freya Z800 800GE高性能的800G以太网测试平台

Xena Freya Z800 800GE 是由全球领先的测试与测量解决方案提供商特励达力科公司&#xff08;Teledyne LeCroy&#xff09;开发的高性能以太网测试平台&#xff0c;专为满足从10GE到800GE数据中心互连速度的需求而设计。特励达力科公司在网络测试领域拥有超过50年的技术积累&…

基于Django框架的股票分红数据爬虫和展示系统

项目截图 一、项目简介 本项目是一个基于 Django 框架的股票分红数据爬虫和展示系统。它可以从东方财富网站爬取股票分红数据&#xff0c;并将数据存储到 Django 数据库中&#xff0c;同时提供数据查询、导出和图表展示功能。该系统为用户提供了一个方便的平台&#xff0c;用于…

nginx性能优化与深度监控

一、性能调优方向 1. 系统层面优化 内核参数调整 TCP队列与连接管理&#xff1a; net.core.somaxconn&#xff08;最大连接队列长度&#xff0c;建议设为65535&#xff09;net.ipv4.tcp_max_syn_backlog&#xff08;SYN队列长度&#xff0c;建议65535&#xff09;net.ipv4.tc…

深入解析 Vision Transformer (ViT) 与其在计算机视觉中的应用

在近年来&#xff0c;深度学习尤其在计算机视觉领域取得了巨大的进展&#xff0c;而 Vision Transformer&#xff08;ViT&#xff09;作为一种新的视觉模型&#xff0c;它的表现甚至在许多任务中超过了传统的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;如 ResNet。在…

PXE_Kickstart_无人值守自动化安装系统

文章目录 1. PXE2. 配置服务参数2.1 tftp服务配置2.2 dhcp服务配置2.3 http服务配置 3. 配置PXE环境3.1 网络引导文件pxelinux.03.2 挂载镜像文件3.3 创建配置文件default3.4 复制镜像文件和驱动文件3.5 修改default文件3.6 配置ks.cfg文件 4. PXE客户端4.1 创建虚拟机&#xf…

鸿蒙NEXT开发动画案例4

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; /*** TODO SpinKit动画组件 - 双粒子旋转缩放动画* author: CSDN-鸿蒙布道师* since: 2025/05/08*/ ComponentV2 export struct SpinFour {// 参数定义Require Param spinSize: number 36…

基于STM32、HAL库的CP2102-GMR USB转UART收发器 驱动程序设计

一、简介: CP2102-GMR是Silicon Labs公司生产的一款USB转UART桥接芯片,主要特点包括: 集成USB 2.0全速功能控制器 内置USB收发器,无需外部电阻 工作电压:3.0V至3.6V 支持的数据格式:数据位8,停止位1,无校验 最高支持1Mbps的波特率 内置512字节接收缓冲区和512字节发送…

Ubuntu 22虚拟机【网络故障】快速解决指南

Ubuntu22虚拟机突然无法连接网络了&#xff0c;以下是故障排除步骤记录。 Ubuntu 22虚拟机网络故障快速解决指南 当在虚拟机中安装的 Ubuntu 22 系统出现 ping: connect: 网络不可达 和 ping: www.baidu.com: 域名解析出现暂时性错误的报错时&#xff0c;通常意味着虚拟机无法…

实战springcloud alibaba

实战springcloud alibaba 前言 如何搭建一套最新的springcloud alibaba&#xff0c;以适配项目升级需求&#xff1f; 1.版本的选择 2.各组件的适配 3.新技术的敏感性 4.前瞻性&#xff0c;几年内不会被淘汰 参考资料&#xff1a;Spring Cloud Alibaba 参考文档 https://spring…

泰迪杯特等奖案例学习资料:基于卷积神经网络与集成学习的网络问政平台留言文本挖掘与分析

(第八届“泰迪杯”数据挖掘挑战赛A题特等奖案例深度解析) 一、案例背景与核心挑战 1.1 应用场景与行业痛点 随着“互联网+政务”的推进,网络问政平台成为政府与民众沟通的重要渠道。某市问政平台日均接收留言超5000条,涉及民生、环保、交通等20余类诉求。然而,传统人工…

DVWA靶场保姆级通关教程--06不安全验证机制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 前言 原理详解 1. 前后端验证逻辑不一致 2. 验证码值保存在客户端 3. 验证码可预测或重复 4. 验证码验证与逻辑解耦 一、处理关卡报错 二、low级别源…

【LeetCode Hot100 | 每日刷题】排序数组

912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 你必须在 不使用任何内置函数 的情况下解决问题&#xff0c;时间复杂度为 O(nlog(n))&#xff0c;并且空间复杂度尽可能小。 示例 1&…

Windows系统下使用Kafka和Zookeeper,Python运行kafka(二)

1.配置 Zookeeper 进入解压后的 Zookeeper 目录&#xff08;例如 F:\zookeeper\conf&#xff09;&#xff0c;复制 zoo_sample.cfg 文件并命名为 zoo.cfg&#xff08;如果 zoo.cfg 已经存在&#xff0c;则直接编辑该文件&#xff09;。 打开 zoo.cfg 文件&#xff0c;配置相关…

Web 自动化之 HTML JavaScript 详解

文章目录 一、HTML 常用标签二、javascript 脚本1、什么是 javascript(js)2、 js变量和函数3、js 弹窗处理4、js 流程控制语句和 switch 结构语句应用 一、HTML 常用标签 HTML&#xff1a;超文本标记语言 超文本&#xff1a;不仅只包含文字&#xff0c;还有超链接、视频…这些…

el-date-picker的type为daterange时仅对开始日期做限制

文章目录 前言绣球html代码一、正确代码二、错误代码 前言绣球 需求是这样的&#xff0c;开始日期需要限制只能选择今天的日期&#xff0c;结束日期只能选择今天之后的日期。结束日期很常见&#xff0c;但是单纯限制开始日期&#xff0c;还是蛮少见的&#xff0c;尤其是datera…

观测云:安全、可信赖的监控观测云服务

引言 近日&#xff0c;“TikTok 遭欧盟隐私监管机构调查并处以 5.3 亿欧元”一案&#xff0c;再次引发行业内对数据合规等话题的热议。据了解&#xff0c;仅 2023 年一年就产生了超过 20 亿美元的 GDPR 罚单。这凸显了在全球化背景下&#xff0c;企业在数据隐私保护方面所面临…

认识中间件-以及两个简单的示例

认识中间件-以及两个简单的示例 什么是中间件一个响应处理中间件老朋友 nest g如何使用为某个module引入全局引入编写逻辑一个日志中间件nest g mi 生成引入思考代码进度什么是中间件 官方文档 中间件是在路由处理程序之前调用的函数。中间件函数可以访问请求和响应对象,以及…