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.mzph.cn/news/821921.shtml

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

相关文章

单链表实现通讯录-三万字

声明 这一篇文章我会从单链表的概念&#xff0c;单链表的原理&#xff0c;一直到通讯录项目单链表的实现&#xff0c;再把单链表的专用题型系统的讲解一下&#xff08;文章较长&#xff09;。同时建议学习单链表之前可以学习一下顺序表&#xff0c;作为知识铺垫顺序表&#xf…

【Java】@RequestMapping注解在类上使用

RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一。这个注解会将 HTTP 请求映射到控制器&#xff08;controller类&#xff09;的处理方法上。 Request Mapping 基础用法 在 Spring MVC 应用程序中&#xff0c;RequestDispatcher (在 Front Controller 之下) 这…

【HCIP学习】OSPF协议基础

一、OSPF基础 1、技术背景&#xff08;RIP中存在的问题&#xff09; RIP中存在最大跳数为15的限制&#xff0c;不能适应大规模组网 周期性发送全部路由信息&#xff0c;占用大量的带宽资源 路由收敛速度慢 以跳数作为度量值 存在路由环路可能性 每隔30秒更新 2、OSPF协议…

Spark-机器学习(2)特征工程之特征提取

在之前的文章中&#xff0c;我们了解我们的机器学习&#xff0c;了解我们spark机器学习中的MLIib算法库&#xff0c;知道它大概的模型&#xff0c;熟悉并认识它。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&a…

【ARFoundation自学01】搭建AR框架,检测平面点击位置克隆物体

Unity开发ARFoundation相关应用首先安装ARFoundation包 然后设置XR 1.基础AR场景框架搭建 2.一个基本的点击克隆物体到识别的平面脚本 挂在XROrigin上 脚本AppController 脚本说明书 ## 业务逻辑 AppController 脚本旨在实现一个基本的 AR 应用程序功能&#xff1a;用户通过…

R语言使用installr包对R包进行整体迁移

今天分享一个R语言的实用小技巧&#xff0c;如果咱们重新安装了电脑&#xff08;我重装了电脑&#xff09;或者因为需要卸载旧版本的R软件&#xff0c;安装新版本的R&#xff0c;那么必然会造成R包的库缺失&#xff0c;需要重新下载&#xff0c;有些还不是官方的R包&#xff0c…

12.模板进阶(模板的全特化,偏特化,声明与定义分离)

1. 非类型模板参数 模板参数分类: 类型形参 与 非类型形参 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当…

爬取东方财富股票代码

我们打开东方财富网站&#xff1a;http://quote.eastmoney.com/stocklist.html 假如懒得爬&#xff0c;也可以用现成的股票数据源&#xff1a;https://stockapi.com.cn 这展示了所有股票信息&#xff0c;不过需要我们分页去爬取 我们可以查询具体的html代码&#xff1a; <…

服装连锁收银软件哪个好用

竞争激烈的服装连锁行业&#xff0c;选择一款高效可靠的收银软件至关重要。商淘云连锁收银软件作为业内领先的解决方案之一&#xff0c;备受关注和好评。本文将介绍商淘云连锁收银软件&#xff0c;并分享其在提升服装连锁店效率和客户体验方面的优势。 1. 商淘云连锁收银软件的…

异地组网如何安装?

【天联】是一款强大的异地组网安装工具&#xff0c;可以帮助企业实现远程设备的统一管理和协同办公。以下是【天联】可以应用的一些场景&#xff1a; 零售、收银软件应用统一管理&#xff1a;【天联】可以结合医药、餐饮、商超等零售业的收银软件&#xff0c;实现异地统一管理。…

OpenHarmony开发案例:【分布式遥控器】

1.概述 目前家庭电视机主要通过其自带的遥控器进行操控&#xff0c;实现的功能较为单一。例如&#xff0c;当我们要在TV端搜索节目时&#xff0c;电视机在遥控器的操控下往往只能完成一些字母或数字的输入&#xff0c;而无法输入其他复杂的内容。分布式遥控器将手机的输入能力…

解决QtCreator不能同时运行多个程序的方法

当我们运行QtCreator代码的时候&#xff0c;往往一个代码&#xff0c;可能需要打开好几个运行&#xff0c;但是会出现的情况就是&#xff0c;如果打开了一个界面&#xff0c;当我么再运行的时候&#xff0c;第一个界面就没有了&#xff0c;而且可能会出现终端报错的情况&#x…

Spectral Adversarial MixUp for Few-Shot Unsupervised Domain Adaptation论文速读

文章目录 Spectral Adversarial MixUp for Few-Shot Unsupervised Domain Adaptation摘要方法Domain-Distance-Modulated Spectral Sensitivity (DoDiSS&#xff09;模块Sensitivity-Guided Spectral Adversarial Mixup (SAMix)模块 实验结果 Spectral Adversarial MixUp for F…

上海计算机学会 2023年10月月赛 乙组T3 树的连通子图(树、树形dp)

第三题&#xff1a;T3树的连通子图 标签&#xff1a;树、树形 d p dp dp题意&#xff1a;给定一棵 n n n个结点的树&#xff0c; 1 1 1号点为这棵树的根。计算这棵树连通子图的个数&#xff0c;答案对 1 , 000 , 000 , 007 1,000,000,007 1,000,000,007取余数。题解&#xff1…

HTML内联框架

前言&#xff1a; 我们有时候打开网页时会有广告窗的出现&#xff0c;而这些窗口并不是来自于本站的&#xff0c;而是来自于外部网页&#xff0c;只是被引用到了自己网页中而已。这一种技术可以通过内联来实现。 标签介绍&#xff1a; HTML 内联框架元素 (<iframe>) 表示…

快速入门Spring Data JPA

Spring Data JPA是Spring Data框架的一小部分&#xff0c;它能够让开发者能够更加简单的对数据库进行增删改查。 由于Spring Data JPA可以自动生成SQL代码所以一般情况下&#xff0c;简单的增删查改就可以交给Spring Data JPA来完成&#xff0c;而复杂的动态SQL等用MyBatis来完…

即插即用模块详解SCConv:用于特征冗余的空间和通道重构卷积

目录 一、摘要 二、创新点说明 2.1 Methodology 2.2SRU for Spatial Redundancy​编辑 2.3CRU for Channel Redundancy 三、实验 3.1基于CIFAR的图像分类 3.2基于ImageNet的图像分类 3.3对象检测 四、代码详解 五、总结 论文&#xff1a;https://openaccess.thecvf.c…

在Qt中如何简单设计一个文件和图像浏览器

文本浏览器 设计一个文本浏览器程序&#xff0c;可以打开、显示 txt、html等文件。 1.在Qt Designer中设计一个菜单其中包含打开和退出选项&#xff1a; 2. 在 QMainWindow 构造函数中把 textBrower 设为主窗口的中心部件&#xff0c;这样整个窗口就成了包含 textBrower 的单文…

你的RPCvs佬的RPC

一、课程目标 了解常见系统库的hook了解frida_rpc 二、工具 教程Demo(更新)jadx-guiVS CodejebIDLE 三、课程内容 1.Hook_Libart libart.so: 在 Android 5.0&#xff08;Lollipop&#xff09;及更高版本中&#xff0c;libart.so 是 Android 运行时&#xff08;ART&#x…

细说postgresql之pg_rman备份恢复 —— 筑梦之路

pg_rman是一款开源的备份恢复软件&#xff0c;支持在线和基于PITR的备份恢复方式。 pg_rman类似于oracle的rman&#xff0c;可以进行全量、增量、归档日志的备份。 运行模式&#xff1a; 安装部署 Releases ossc-db/pg_rman GitHub 1、需要根据PG Server的版本&#xff0c;下…