嵌入式 __sync_fetch_and_add系列函数

本文详细介绍了__sync_fetch_and_add系列函数的使用方法及其在多线程环境下的应用,包括加、减、与、或、异或等原子性操作,并探讨了memory barrier的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

__sync_fetch_and_add系列的命令,发现这个系列命令讲的最好的一篇文章,英文好的同学可以直接去看原文。Multithreaded simple data type access and atomic variables
    __sync_fetch_and_add系列一共有十二个函数,有加/减/与/或/异或/等函数的原子性操作函数,__sync_fetch_and_add,顾名思义,现fetch,然后自加,返回的是自加以前的值。以count = 4为例,调用__sync_fetch_and_add(&count,1),之后,返回值是4,然后,count变成了5.
   有__sync_fetch_and_add,自然也就有__sync_add_and_fetch,呵呵这个的意思就很清楚了,先自加,在返回。他们哥俩的关系与i++和++i的关系是一样的。被谭浩强他老人家收过保护费的都会清楚了。
   有了这个宝贝函数,我们就有新的解决办法了。对于多线程对全局变量进行自加,我们就再也不用理线程锁了。下面这行代码,和上面被pthread_mutex保护的那行代码作用是一样的,而且也是线程安全的。
__sync_fetch_and_add( &global_int, 1 );
   下面是这群函数的全家福,大家看名字就知道是这些函数是干啥的了。
在用gcc编译的时候要加上选项 -march=i686
type __sync_fetch_and_add (type *ptr, type value);
type __sync_fetch_and_sub (type *ptr, type value);
type __sync_fetch_and_or (type *ptr, type value);
type __sync_fetch_and_and (type *ptr, type value);
type __sync_fetch_and_xor (type *ptr, type value);
type __sync_fetch_and_nand (type *ptr, type value);
type __sync_add_and_fetch (type *ptr, type value);
type __sync_sub_and_fetch (type *ptr, type value);
type __sync_or_and_fetch (type *ptr, type value);
type __sync_and_and_fetch (type *ptr, type value);
type __sync_xor_and_fetch (type *ptr, type value);
type __sync_nand_and_fetch (type *ptr, type value);

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

这两个函数提供原子的比较和交换,如果*ptr == oldval,就将newval写入*ptr,
第一个函数在相等并写入的情况下返回true.
第二个函数在返回操作之前的值。

__sync_synchronize (...)
发出一个full barrier.

关于memory barrier,cpu会对我们的指令进行排序,一般说来会提高程序的效率,但有时候可能造成我们不希望得到的结果,举一个例子,比如我们有一个硬件设备,它有4个寄存器,当你发出一个操作指令的时候,一个寄存器存的是你的操作指令(比如READ),两个寄存器存的是参数(比如是地址和size),最后一个寄存器是控制寄存器,在所有的参数都设置好之后向其发出指令,设备开始读取参数,执行命令,程序可能如下:
write1(dev.register_size,size);
   write1(dev.register_addr,addr);
   write1(dev.register_cmd,READ);
   write1(dev.register_control,GO);
如果最后一条write1被换到了前几条语句之前,那么肯定不是我们所期望的,这时候我们可以在最后一条语句之前加入一个memory barrier,强制cpu执行完前面的写入以后再执行最后一条:
write1(dev.register_size,size);
   write1(dev.register_addr,addr);
   write1(dev.register_cmd,READ);
   __sync_synchronize();
   write1(dev.register_control,GO);

memory barrier有几种类型:
   acquire barrier : 不允许将barrier之后的内存读取指令移到barrier之前(linux kernel中的wmb())。
   release barrier : 不允许将barrier之前的内存读取指令移到barrier之后 (linux kernel中的rmb())。
   full barrier    : 以上两种barrier的合集(linux kernel中的mb())。


还有两个函数:

type __sync_lock_test_and_set (type *ptr, type value, ...)
  将*ptr设为value并返回*ptr操作之前的值。

void __sync_lock_release (type *ptr, ...)
    将*ptr置0

### 关于 `__sync_fetch_and_add` 的使用说明 #### 函数定义 `__sync_fetch_and_add` 是 GCC 提供的一组内置原子操作函数之一,用于执行线程安全的操作。它实现了对指定内存位置的值进行原子性的获取并增加功能[^3]。 该函数的形式如下: ```c type __sync_fetch_and_add (type *ptr, type value); ``` 其中: - `ptr`: 指向目标变量的指针。 - `value`: 需要加到目标变量上的数值。 - 返回值: 原始的目标变量值(即未增加前的值)。 #### 数据类型的限制 需要注意的是,`__sync_fetch_and_add` 对数据类型有一定的约束条件。支持的数据类型仅限于整数类型及其无符号版本,具体包括 `int`, `long`, `long long` 和它们的无符号形式。如果尝试使用其他类型,则可能导致编译错误或运行时异常[^4]。 #### 编译器选项的要求 为了正确地生成针对特定处理器架构的支持指令集扩展代码,在使用这些同步原语时通常需要显式指定 `-march=` 参数给 gcc 编译器。例如,当目标机器为 i686 架构时应加入 `-march=i686` 作为编译参数。 #### 工作原理与行为描述 此函数会先读取由 ptr 所指向地址处存储的内容,并将其保存下来;接着在同一时刻对该内容加上第二个参数所给出的增量值并将更新后的结果写回同一地址之中完成整个过程而不会受到任何干扰从而保证了其原子性质。最终返回原始未经修改之前位于该位置中的旧值。 以下是具体的例子展示如何应用这一机制来实现简单的计数器逻辑: ```c #include <stdio.h> #include <stdint.h> volatile uint32_t counter; void increment_counter(void){ uint32_t old_value; do { old_value = __sync_fetch_and_add(&counter, 1); // Atomic fetch-and-add operation. } while(0); printf("Old Value:%u New Value:%u\n",old_value,(uint32_t)(old_value+1)); } int main(){ counter=0; increment_counter(); // First call increments from 0 -> prints Old Value:0 New Value:1 increment_counter(); // Second call increments from 1 -> prints Old Value:1 New Value:2 return 0; } ``` 在这个程序里展示了通过调用两次increment_counter函数分别使得初始状态下的零增长至一再进一步增至二的过程同时验证每次操作前后相应变化情况均符合预期效果证明了上述方法确实能够达到目的并且具备良好的可移植性和效率表现特点。 #### 多线程环境下的优势 由于此类操作天然具有不可分割特性因此非常适合应用于并发场景当中替代传统意义上较为复杂低效的手动管理互斥量方式达成相同的目的同时还简化了编程模型降低了维护成本提高了整体性能水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值