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;
}

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

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

相关文章

Python --- 在python中安装NumPy,SciPy和Matplotlib(Windows平台)

在python中安装NumPy&#xff0c;SciPy和Matplotlib(Windows平台) NumPy NumPy是Python的一个最常用最基本的扩展程序库之一&#xff0c;主要用于矩阵运算或数组计算。很多其他的python库都要依赖于NumPy才能跑。 NumPy的发展史&#xff1a; Matrix-sig 1995年&#xff0c;特殊…

javaWeb项目-快捷酒店管理系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Spring Boot框架 …

绝地求生:PCL大名单公布,艾伦格三巨头惨遭拆散

就在4.16号PCL官博公布了春季赛的参赛大名单&#xff0c;此次比赛不再像以前一样分为艾伦格、米拉玛和维寒迪三组&#xff0c;而是重新打乱分成了A、B、C三组。 具体名单如下 不仅多了很多新战队&#xff0c;还有一些老家伙也回到了赛场上&#xff0c;比如四大名捕的TSG。

FMEA赋能可穿戴设备:打造安全可靠的未来科技新宠!

在科技日新月异的今天&#xff0c;可穿戴设备已成为我们生活中不可或缺的一部分。它们以其便携性、智能化和个性化的特点&#xff0c;深受消费者喜爱。然而&#xff0c;随着可穿戴设备市场的快速扩张&#xff0c;其安全性和可靠性问题也日益凸显。为了确保产品质量&#xff0c;…

Opentelemetry——Sampling

Sampling 采样 Learn about sampling, and the different sampling options available in OpenTelemetry. 了解采样以及 OpenTelemetry 中提供的不同采样选项。 With distributed tracing, you observe requests as they move from one service to another in a distributed…

【六】fastapi+vue前后端分离项目

前端代码 https://gitee.com/feiminjie/helloworldfront 后端代码 https://gitee.com/feiminjie/helloworld 整体效果 首页 用例管理页 用例详情页

设计模式—门面模式

定义: 门面模式,也称为外观模式&#xff0c;是一种结构型设计模式。它的主要目的是提供统一的接口来访问子系统中的多个接口&#xff0c;从而简化客户端与复杂子系统之间的交互。 在门面模式中&#xff0c;一个门面类充当中介&#xff0c;为客户端提供一个简化了的访问方式&…

OpenStack:开源云计算的崛起与发展

目录 一&#xff0c;引言 二&#xff0c;OpenStack的起源 三&#xff0c;OpenStack的版本演进 四&#xff0c;OpenStack跟虚拟化的区别 五&#xff0c;OpenStack组件介绍 1&#xff09;Horizon介绍 2&#xff09;KeyStone介绍 Keystone 功能概览 Keystone 架构详解 3&a…

【ElasticSearch】安装

1.官网寻找合适版本下载 这里我选择的是8.11.1 2.解压并启动 然后在浏览器输入http://localhost:9200/&#xff0c;判断是否启动成功 如下所示&#xff0c;则表示启动成功 安装过程中遇到过几个bug&#xff0c;记录在这篇文章中 【ElasticSearch】安装&#xff08;bug篇&am…

聚道云软件连接器助力企业实现滴滴出差报销自动化

一、客户介绍 某机械有限公司是一家在机械设备制造领域拥有深厚底蕴和卓越实力的企业。自公司成立以来&#xff0c;该公司始终秉承创新、务实、高效的发展理念&#xff0c;专注于机械设备的研发、生产和销售。经过多年的发展&#xff0c;公司已成为国内机械行业的佼佼者&#…

分享一个纯HTML的后台数据统计管理UI框架模板源码

纯HTML的后台数据统计管理UI框架模板源码 有很多好看的样式 以及各种图表 表格 大量的图标 源码 <!DOCTYPE html> <html lang"en"><head><!-- Required meta tags --><meta charset"utf-8"><meta name"viewport&qu…

Vue Router基础知识整理

Vue Router基础知识整理 1. 安装与使用&#xff08;Vue3&#xff09;安装使用 2. 配置路径别名和VSCode路径提示&#xff08;了解&#xff09;3. 使用查询字符串或路径传参query动态路由 与 params 4. router-link、定义别名、定义路由名称、编程式导航定义别名 aliasrouter-li…