linux内核关于宏READ_ONCE的学习记录

路径://alps/kernel-5.10/tools/include/linux/compiler.h

相关源码:

#define READ_ONCE(x)                                    \
({                                                      \
        union { typeof(x) __val; char __c[1]; } __u =   \
                { .__c = { 0 } };                       \
        __read_once_size(&(x), __u.__c, sizeof(x));     \
        __u.__val;                                      \
})


void __read_once_size(const volatile void *p, void *res, int size)
{
        switch (size) {                                                 \
        case 1: *(unsigned char *)res = *(volatile unsigned char *)p; break;              \
        case 2: *(unsigned short *)res = *(volatile unsigned short *)p; break;            \
        case 4: *(unsigned int *)res = *(volatile unsigned int *)p; break;            \
        case 8: *(unsigned long long *)res = *(volatile unsigned long long *)p; break;            \
        default:                                                        \
                barrier();                                              \
                __builtin_memcpy((void *)res, (const void *)p, size);   \
                barrier();                                              \
        }                                                               \
}

#define barrier() asm volatile("" ::: "memory")

源码分析:

        READ_ONCE(x) 是一个宏,用于读取变量 x 的值,并确保这个读取操作在多线程环境中是原子的。该宏的实现如下:

  • 它创建了一个联合体 __u,它有两个成员:__val 和 __c。创建联合体的目的是通过将变量 x 当作字符数组来解释,以便读取其值。
  • 初始化 __u.__c 数组的所有元素为零,以确保初始状态下 __u.__val 的值为零。
  • 调用函数 __read_once_size 来实际执行读取操作。它将 x 的地址、__u.__c 数组的地址以及 x 的大小传递给函数。
  • 最后,返回 __u.__val,即读取到的值。

__read_once_size 函数根据传入的大小参数 size 执行不同的读取操作。

  • 如果 size 是 1、2、4 或 8 中的一个,表示要读取的数据类型是 unsigned char、unsigned short、unsigned int 或 unsigned long long。在这种情况下,函数会将 p 指向的内容读取到 res 指向的内存位置。
  • 如果 size 不满足上述条件,即要读取的数据类型大小不固定,那么函数会执行一对内存屏障(barrier)。内存屏障用于确保在它们之前和之后的内存访问操作按照预期顺序执行,并且不会被重排序。然后,函数使用内置函数 __builtin_memcpyp 指向的数据复制到 res 指向的内存位置。

        宏定义 barrier() 是一条汇编指令,用于创建一个内存屏障。它在需要确保内存访问顺序的地方使用。内存屏障可以防止编译器和处理器对内存访问进行重排序,以确保操作的正确性和一致性。

        为什么不是直接读取变量值,而是如此大费周折的去读取一个变量呢,目的是为了能够安全地读取变量值,特别是在多线程环境中,确保读取操作是原子的,并且使在读取大小不固定的情况下也能保持正确性。

参考:Linux内核中的READ_ONCE和WRITE_ONCE宏-CSDN博客

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值