简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻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,可以安全地进行下一步操作
}
- 在这个例子中,
thread1
将x
的值设置为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;
}