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…

FreeRTOS 4.16作业

1、总结keil5下载代码和编译代码需要注意的事项 1&#xff09;使用STM32Cubemx创建工程 2&#xff09;先build编译排除错误 3&#xff09;点击魔术棒&#xff0c;选择Debug选项&#xff0c;找到使用的仿真器&#xff0c;选择ST-LINK仿真器&#xff0c;点击settings&#xff…

62、ARM/STM32开发板按键中断相关学习20240416

实现开发板上三个按键按下后触发中断&#xff0c;控制LED灯的亮灭。 【本次实验现象为&#xff1a;按键1&#xff08;key1&#xff09;控制开灯&#xff0c;key3控制关灯&#xff0c;key2按下LED灯闪烁五次】 代码&#xff1a; 头文件mykey.h: #ifndef __MYKEY_H__ #define…

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

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

Google Guava第五讲:本地缓存实战及踩坑

本地缓存实战及踩坑 本文是Google Guava第五讲,先介绍为什么使用本地缓存;然后结合实际业务,讲解如何使用本地缓存、清理本地缓存,以及使用过程中踩过的坑。 文章目录 本地缓存实战及踩坑1、缓存系统概述2、缓存架构演变2.1、无缓存架构2.2、引入分布式缓存问题1:为什么选…

【HCIP学习】OSPF协议基础

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

用ChatGPT轻松撰写出色论文

ChatGPT无限次数:点击直达 用ChatGPT轻松撰写出色论文 在当今信息爆炸的时代&#xff0c;写作是一项必不可少的技能。无论是学术论文、科技报道还是人文文学&#xff0c;写作都扮演着重要的角色。然而&#xff0c;写作并非每个人的强项&#xff0c;有时候我们会遇到写作灵感枯…

Python中的GIL(全局解释器锁):理解其对多线程编程的影响

Python中的GIL&#xff08;全局解释器锁&#xff09;&#xff1a;理解其对多线程编程的影响 在深入探讨Python编程的高级主题时&#xff0c;全局解释器锁&#xff08;GIL&#xff09;是一个不可忽视的概念。GIL是Python解释器中的一个互斥锁&#xff0c;它对多线程编程有着显著…

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. 商淘云连锁收银软件的…

ChatGPT:打造高质量论文的秘密武器

ChatGPT无限次数:点击直达 ChatGPT&#xff1a;打造高质量论文的秘密武器 在当今信息爆炸的时代&#xff0c;高质量的论文写作对于学术研究者和科技领域的从业者来说至关重要。然而&#xff0c;写作是一项需要耗费大量时间和精力的任务&#xff0c;在写作过程中还常常会遇到思…

go服务k8s容器化之grpc负载均衡

理论&#xff1a; 1.grpc基于HTTP/2实现&#xff0c;HTTP2是长连接的&#xff0c;io多路复用&#xff0c;即在一条tcp连接上可以发起多个rpc请求, 请求通过流id 也就是streamID划分。 2.k8s是L4层负载均衡&#xff0c;也就是TCP那层&#xff0c;支持tcp的流量转发&#xff0c;…

异地组网如何安装?

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

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

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

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

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

【云计算】混合云组成、应用场景、风险挑战

《混合云》系列&#xff0c;共包含以下 3 篇文章&#xff1a; 【云计算】混合云概述【云计算】混合云分类【云计算】混合云组成、应用场景、风险挑战 &#x1f60a; 如果您觉得这篇文章有用 ✔️ 的话&#xff0c;请给博主一个一键三连 &#x1f680;&#x1f680;&#x1f68…