Linux内核之WRITE_ONCE用法实例(四十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.Linux内核之WRITE_ONCE介绍
    • 🌻3.代码实例
      • 🐓3.1 原子写入变量值
      • 🐓3.2 原子写入结构体成员
      • 🐓3.3 原子写入数组元素

🌻1.前言

本篇目的:Linux内核之WRITE_ONCE用法实例

🌻2.Linux内核之WRITE_ONCE介绍

  • WRITE_ONCE是一个宏,它在Linux内核中用于确保对变量的写操作是原子性的,并且不会被编译器的优化重排。这个宏的主要目的是在多线程环境中提供一种安全的方式来写入共享变量,确保其他线程能够看到正确的值。
  • WRITE_ONCE宏的实现利用了C语言的结构体和联合体的特性。首先,它定义了一个匿名联合体,其中包含一个与目标变量x类型相同的成员__val,以及一个字符数组__c。这个字符数组的大小设置为1,是为了确保联合体的大小与x的大小相同。
  • 然后,宏将值val转换为x的类型,并将其赋值给联合体的__val成员。这个转换使用了__force关键字,它是一个类型转换提示,告诉编译器这个转换是故意的,不应该被优化掉。
  • 接下来,宏调用了一个名为__write_once_size的函数,它接受三个参数:目标变量x的地址、联合体的字符数组的地址,以及目标变量x的大小。这个函数负责执行实际的写操作,确保写入是原子性的,并且不会被重排。
  • 最后,宏返回联合体的__val成员的值,这通常是写入的值val
  • WRITE_ONCE宏的使用确保了在多核处理器上的写操作是原子的,并且不会被编译器的优化重排。这在多线程编程中非常重要,因为它确保了其他线程能够看到正确的值,即使在高并发的情况下。
  • 例如,考虑以下情况:
int x = 0;
void thread1() {
    WRITE_ONCE(x, 1);
}
void thread2() {
    while (x == 0) {
        // 自旋等待x变为1
    }
    // x现在是1,可以安全地进行下一步操作
}
  • 在这个例子中,thread1x的值设置为1,而thread2则在x变为1之前自旋等待。由于WRITE_ONCE确保了写操作的原子性和可见性,thread2将能够看到thread1写入的值,并且可以安全地进行下一步操作。
  • WRITE_ONCE是一个在Linux内核中用于提供原子性和可见性保证的宏。它通过利用联合体和特殊的写操作函数来确保对共享变量的写操作是安全的,不会被编译器的优化重排。这在多线程编程中非常重要,可以避免竞态条件和数据不一致的问题。

🌻3.代码实例

🐓3.1 原子写入变量值

#include <stdio.h>

// 定义 WRITE_ONCE 宏
#define WRITE_ONCE(x, val)				\
  ({							\
    union { typeof(x) __val; char __c[1]; }             \
    __u = { .__val = (__typeof__(x)) (val) };		\
    __write_once_size(&(x), __u.__c, sizeof(x));	\
    __u.__val;						\
  })

// 模拟写入操作
void __write_once_size(void *addr, const void *buffer, int size) {
  printf("Writing %d bytes to address %p\n", size, addr);
  printf("%s(), line = %d, addr = %d, buffer = %d\n",__FUNCTION__,__LINE__,*(int*)addr, *(int*)buffer);
}

int main() {
  int value = 0;
  int new_value = WRITE_ONCE(value, 10);

  printf("Original value: %d\n", value);
  printf("New value: %d\n\n", new_value);

  int vv = 111;
  int ret = WRITE_ONCE(vv, 123);
  printf("ret =  %d\n", ret);

  return 0;
}


🐓3.2 原子写入结构体成员

#include <stdio.h>

struct MyStruct {
    int a;
    float b;
};

// 定义 WRITE_ONCE 宏
#define WRITE_ONCE(x, val) \
({ \
    union { typeof(x) __val; char __c[1]; } __u = \
        { .__val = (__typeof__(x)) (val) }; \
    __write_once_size(&(x), __u.__c, sizeof(x)); \
    __u.__val; \
})

// 模拟写入操作
void __write_once_size(void *addr, const void *buffer, int size) {
    printf("Writing %d bytes to address %p\n", size, addr);
}

int main() {
    struct MyStruct data;
    data.a = 0;
    data.b = 0.0f;

    struct MyStruct new_data = {WRITE_ONCE(data.a, 5), WRITE_ONCE(data.b, 3.14f)};

    printf("Original struct: a = %d, b = %f\n", data.a, data.b);
    printf("New struct: a = %d, b = %f\n", new_data.a, new_data.b);

    return 0;
}

🐓3.3 原子写入数组元素

#include <stdio.h>

#define ARRAY_SIZE 5

// 定义 WRITE_ONCE 宏
#define WRITE_ONCE(x, val) \
({ \
    union { typeof(x) __val; char __c[1]; } __u = \
        { .__val = (__typeof__(x)) (val) }; \
    __write_once_size(&(x), __u.__c, sizeof(x)); \
    __u.__val; \
})

// 模拟写入操作
void __write_once_size(void *addr, const void *buffer, int size) {
    printf("Writing %d bytes to address %p\n", size, addr);
}

int main() {
    int array[ARRAY_SIZE] = {0};

    for (int i = 0; i < ARRAY_SIZE; ++i) {
        array[i] = WRITE_ONCE(array[i], i * 2);
    }

    printf("Array after writing:\n");
    for (int i = 0; i < ARRAY_SIZE; ++i) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stm32实现hid键盘

前面的cubelmx项目配置参考 stm32实现hid鼠标-CSDN博客https://blog.csdn.net/anlog/article/details/137814494?spm1001.2014.3001.5502两个项目的配置完全相同。 代码 引用 键盘代码&#xff1a; 替换hid设备描述符 先屏蔽鼠标设备描述符 替换为键盘设备描述符 修改宏定…

深度学习 Lecture 7 迁移学习、精确率、召回率和F1评分

一、迁移学习&#xff08;Transfer learning) 用来自不同任务的数据来帮助我解决当前任务。 场景&#xff1a;比如现在我想要识别从0到9度手写数字&#xff0c;但是我没有那么多手写数字的带标签数据。我可以找到一个很大的数据集&#xff0c;比如有一百万张图片的猫、狗、汽…

基于Adaboost模型的数据预测和分类matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 AdaBoost&#xff08;Adaptive Boosting&#xff09;是一种集成学习方法&#xff0c;由Yoav Freund和Robert Schapire于1995年提出&#xff0c;主要用于提高弱分类…

UML 介绍

前言 UML 简介。 文章目录 前言一、简介1、事务2、关系1&#xff09;依赖2&#xff09;关联聚合组合 3&#xff09;泛化4&#xff09;实现 二、类图三、对象图四、用例图五、交互图1、序列图&#xff08;顺序图&#xff09;2、通信图 六、状态图七、活动图八、构件图&#xff0…

详解UART通信协议以及FPGA实现

文章目录 一、UART概述二、UART协议帧格式2.1 波特率2.2 奇校验ODD2.3 偶校验EVEN 三、UART接收器设计3.1 接收时序图3.2 Verilog代码3.3 仿真文件测试3.4 仿真结果3.5 上版测试 四、UART发送器设计4.1 发送时序图4.2 Verilog代码4.3 仿真文件测试4.4 仿真结果4.5 上板测试 五、…

HarmonyOS开发实战:【亲子拼图游戏】

概述 本篇Codelab是基于TS扩展的声明式开发范式编程语言编写的一个分布式益智拼图游戏&#xff0c;可以两台设备同时开启一局拼图游戏&#xff0c;每次点击九宫格内的图片&#xff0c;都会同步更新两台设备的图片位置。效果图如下&#xff1a; 说明&#xff1a; 本示例涉及使…

2016NOIP普及组真题 1. 金币

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1969 核心思想&#xff1a; 解法1、由于数据量只有 10000 天&#xff0c;估可以采用 模拟每一天 的方式。 #include <bits/stdc.h> using namespace std;int k 0;int main() {i…

SpringBoot项目基于java的教学辅助平台

采用技术 SpringBoot项目基于java的教学辅助平台的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 学生信息管理 教师信息管理 课程信息管理 科目分类管…

【面试经典 150 | 链表】K 个一组翻转链表

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;迭代 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

xxl-job使用自动注册节点,ip不对,如何解决????

很明显这时我们本机的ip和我们xxl-job自动注册的ip是不一致的&#xff0c;此时该如何处理呢&#xff1f;&#xff1f;&#xff1f;&#xff1f; 方法一&#xff1a;在配置文件中&#xff0c;将我们的ip固定写好。 ### xxl-job executor server-info xxl.job.executor.ip写你的…

pandas基本用法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas的数据结构1、一维数组pd.Series1.1 pd.Series&#xff08;data,index,dtype&#xff09;示例1&#xff1a;不定义index示例2&#xff1a;自定义inde…

基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于HMM隐马尔可夫模型的金融数据预测算法.程序实现HMM模型的训练&#xff0c;使用训练后的模型进行预测。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运…

excel 无法正确处理 1900-03-01 前的日期

问题由来&#xff1a;excel 用公式 TEXT(A1,"yyyy-mm-dd") 转日期时&#xff0c;当A1 的值等于59 的时候&#xff0c;返回值是1900-02-28&#xff1b;当A1 的值等于61 的时候&#xff0c;返回值是1900-03-01&#xff1b;那么当 A1的值为 60 的时候&#xff0c;返回值…

数图智慧零售解决方案,赋能零售行业空间资源价值最大化

数图智慧零售解决方案 赋能零售行业空间资源价值最大 在激烈的市场竞争中&#xff0c;如何更好地提升空间资源价值&#xff0c;提高销售额&#xff0c;成为行业关注的焦点。近日&#xff0c;NIQ发布的《2024年中国饮料行业趋势与展望》称&#xff0c;“在传统零售业态店内&…

第十一章数据仓库和商务智能10分

【数据仓库-后端&#xff0c;商务智能-前端】 基本算法&#xff1a;关联关系&#xff08;牵手-谈恋爱&#xff09;&#xff0c;集群关系&#xff08;杭州人爱吃酸甜口&#xff09;&#xff0c;决策树&#xff0c;线性回归&#xff0c;贝叶斯&#xff0c;神经网络&#xff0c;时…

Adobe AE(After Effects)2015下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

使用大模型来实现医疗领域的隐私信息保护

大模型隐私主要分为训练阶段、推理阶段以及用户与大模型交互过程中的隐私泄露&#xff0c;目前的研究重点在大模型训练阶段。传统隐私保护技术主要包括联邦学习、差分隐私、同态加密等&#xff0c;这些技术在大模型背景下的应用挑战不断加剧&#xff1a;(1)联邦学习应用于大模型…

ArkTs

一、概述 ArkTs是由TypeScript扩展而来&#xff0c;在继承TypeScript语法的基础上进行了一系列优化&#xff0c;使开发者能够以更简洁、更自然的方式开发应用。 TypeScript语法: 线上网站:https://www.typescriptlang.org/zh/play 二、TS变量 变量声明: 常量声明: const b…

【高端电流检测IC储能产品应用方案】耐压45V侧轨的电流检测芯片FP137 应用于电脑电源,开关电源以及多口快充充电器,户外移动电源,适配器,电池充电器等

近年来&#xff0c;随着电子产品的飞速发展&#xff0c;对电流检测精度和可靠性的要求也越来越高。特别是在电脑电源、开关电源以及多口快充充电器、户外移动电源、适配器、电池充电器等领域&#xff0c;对电流检测技术的需求更是日益增长。 电流检测芯片是一种关键的电子元器…

强化学习(三)基于动态规划 Dynamic Programming 的求解方法

文章目录 1. 动态规划与强化学习的联系2. 利用动态规划求解最优价值函数2.1 案例背景2.2 策略评估&#xff08;预测&#xff09;2.3 策略迭代&#xff08;控制&#xff09; 在前文《强化学习的数学框架&#xff1a;马尔科夫决策过程 MDP》中&#xff0c;我们用马尔可夫过程抽象…