GCC 提供的原子操作总结

本文介绍了GCC自4.1.2版本起提供的__sync_*系列内置函数,这些函数可用于执行原子性的加减及逻辑运算。文章详细解释了这些函数的用法、参数意义,并通过示例代码展示了如何使用__sync_fetch_and_add进行线程安全的计数器递增。
gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作。

其声明如下:

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, ...)




这两组函数的区别在于第一组返回更新前的值,第二组返回更新后的值。

type可以是1,2,4或8字节长度的int类型,即:

int8_t 
/ uint8_t
int16_t 
/ uint16_t
int32_t 
/ uint32_t
int64_t 
/ uint64_t



后面的可扩展参数(...)用来指出哪些变量需要memory barrier,因为目前gcc实现的是full barrier(类似于linux kernel 中的mb(),表示这个操作之前的所有内存操作不会被重排序到这个操作之后),所以可以略掉这个参数。


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


示例程序:

#include 
<stdio.h>
#include 
<pthread.h>
#include 
<stdlib.h>

static int count = 0;


void *test_func(void *arg)
{
        
int i=0;
        
for(i=0;i<20000;++i){
                __sync_fetch_and_add(
&count,1);
        }
        
return NULL;
}

int main(int argc, const char *argv[])
{
        pthread_t id[
20];
        
int i = 0;

        
for(i=0;i<20;++i){
                pthread_create(
&id[i],NULL,test_func,NULL);
        }

        
for(i=0;i<20;++i){
                pthread_join(id[i],NULL);
        }

        printf(
"%d\n",count);
        
return 0;
}
<think>首先,用户的问题是关于GCC提供的函数和扩展功能。用户提到了GCC,即GNU Compiler Collection,它支持多种编程语言,包括C和C++,并提供各种扩展功能。 回顾系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 用户可见层要求: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考的引用内容: - [^1]: 关于GCC的full barrier和memory barrier的讨论。 - [^2]: 关于GCC C语言扩展的介绍,包括函数属性、变量属性、内联汇编等。 - [^3]: 关于内嵌函数(nested functions)在GCC中的使用。 - [^4]: 关于GCC在链接时选择动态库还是静态库的优先顺序。 用户意图似乎是查找与GCC提供的函数或功能相关的信息,可能包括编译器扩展、内建函数等。 结构化回答: 1. **介绍GCC的功能**:简要解释GCC是什么,以及它提供的扩展功能。 2. **详细描述关键功能**:基于引用,讨论GCC的扩展,如函数属性、变量属性、内联汇编、内建函数(包括原子操作)、内嵌函数等。 3. **举例说明**:提供代码示例来演示这些功能。 4. **生成相关问题**:在回答结束时,添加相关问题。 关键点从引用中提取: - [^2] 提到GCC C语言扩展:函数属性、变量属性、内联汇编、原子操作相关的内建函数。 - [^3] 讨论内嵌函数(nested functions),这在标准C中不直接支持,但GCC提供。 - [^1] 涉及原子操作和内存屏障的内建函数。 - [^4] 是关于库链接的,但可能不直接相关,除非用户提到库。 用户问题:“请问GCC 提供的函数和扩展功能”,所以焦点在GCC的扩展功能。 大纲回答: - **步骤1:介绍GCC扩展**:GCC提供许多扩展来增强C和C++语言,包括内建函数、属性、内联汇编等。 - **步骤2:详细功能**: - 函数属性:如 `__attribute__((...))` 用于优化或控制行为。 - 变量属性:类似,用于变量。 - 内联汇编:允许在C代码中嵌入汇编指令。 - 原子操作内建函数:如 `__atomic_*` 用于线程安全操作。 - 内嵌函数:GCC支持在函数内部定义函数(nested functions)。 - **步骤3:代码示例**:从引用中取例子或创建简单例子。 - **步骤4:总结**:强调这些扩展的用途。 - **步骤5:生成相关问题**:添加3-5个相关问题。 确保使用中文回答。 数学表达式:如果提到数学相关,如内存模型,使用$...$。例如,在原子操作中,可能有内存顺序模型,提到时用数学格式。 例如,如果讨论原子操作,可以说:GCC原子内建函数确保操作如$ \text{load} $ 和 $ \text{store} $ 遵守特定内存顺序。 引用标识:在回答中引用段落时,末尾添加[^n]。 相关问题:基于主题生成,如: 1. GCC内建函数的具体用法是什么? 2. 如何优化代码使用GCC属性? 3. GCC支持哪些原子操作类型? 现在,构建回答。</think>### GCC 提供的函数和扩展功能 GCC(GNU Compiler Collection)是广泛使用的开源编译器套件,支持多种编程语言(如C、C++)。除了标准语言特性外,GCC 提供了丰富的扩展功能,这些功能通过编译器特定的内建函数(built-in functions)、属性(attributes)和内联汇编(inline assembly)等实现,以提升性能、优化代码或支持底层硬件操作。以下我将逐步介绍 GCC 的主要扩展功能,帮助您全面理解。回答基于真实可靠的 GCC 文档和相关技术资料[^1][^2][^3]。 #### 1. **函数属性(Function Attributes)** GCC 允许通过 `__attribute__((...))` 语法为函数添加特定属性,以控制编译器行为。例如: - `__attribute__((always_inline))`:强制内联函数,避免函数调用开销。 - `__attribute__((noreturn))`:表示函数永不返回(如 `exit()`)。 - `__attribute__((weak))`:声明弱符号,便于链接时覆盖。 示例代码(C语言): ```c #include <stdio.h> // 使用 always_inline 属性强制内联 static inline __attribute__((always_inline)) void print_hello() { printf("Hello, GCC!\n"); } int main() { print_hello(); // 编译器会内联展开此调用 return 0; } ``` 这些属性优化了代码生成,减少执行时间[^2]。 #### 2. **变量属性(Variable Attributes)** 类似函数属性,GCC 允许为变量添加属性以控制内存布局或优化: - `__attribute__((aligned(16)))`:强制变量对齐到16字节边界,提升 SIMD 指令效率。 - `__attribute__((unused))`:抑制未使用变量的警告。 - `__attribute__((cleanup))`:自动清理资源(如自动释放内存)。 示例: ```c int var __attribute__((aligned(16))); // 变量对齐到16字节 ``` 这在嵌入式系统或高性能计算中尤为重要[^2]。 #### 3. **内联汇编(Inline Assembly)** GCC 支持在 C/C++ 代码中直接嵌入汇编指令,用于底层硬件操作或性能关键路径。语法为 `asm volatile(...)`,其中 `volatile` 防止编译器优化。 - 基本格式:`asm volatile("汇编指令" : 输出操作数 : 输入操作数 : 破坏寄存器列表);` 示例(计算两个数的和): ```c int add(int a, int b) { int result; asm volatile ( "add %[a], %[b], %[result]" : [result] "=r" (result) // 输出操作数 : [a] "r" (a), [b] "r" (b) // 输入操作数 : "cc" // 破坏标志寄存器 ); return result; } ``` 内联汇编常用于操作系统内核或驱动开发[^2]。 #### 4. **原子操作内建函数(Atomic Built-in Functions)** GCC 提供一组内建函数用于原子操作,确保多线程环境下的内存安全。这些函数基于内存模型(如顺序一致性),使用 `__atomic_*` 前缀: - `__atomic_load_n(ptr, order)`:原子加载值,遵守内存顺序 $ \text{order} $(例如 $ \text{__ATOMIC_SEQ_CST} $ 表示顺序一致性)。 - `__atomic_store_n(ptr, value, order)`:原子存储值。 - `__atomic_fetch_add(ptr, value, order)`:原子加法。 内存顺序模型涉及数学概念,如操作顺序约束:$ \text{load} \rightarrow \text{store} $ 表示加载操作必须在存储之前完成[^1]。GCC 默认实现 full barrier(类似 Linux kernel 的 `mb()`),防止指令重排序[^1]。 示例(原子计数器): ```c #include <stdatomic.h> atomic_int counter = ATOMIC_VAR_INIT(0); void increment() { __atomic_fetch_add(&counter, 1, __ATOMIC_SEQ_CST); // 原子增加 } ``` #### 5. **内嵌函数(Nested Functions)** GCC 支持在函数内部定义函数(内嵌函数),这在标准 C 中无效,但 GCC 通过扩展实现。内嵌函数可以访问外部函数的局部变量,便于封装逻辑。 - 示例:内嵌函数作为参数传递或存储地址。 ```c #include <stdio.h> typedef int(*func)(); // 函数指针类型 func get_func() { int n = 0; int increment() { // 内嵌函数定义 return ++n; } return increment; // 返回内嵌函数地址 } int main() { func f = get_func(); printf("%d\n", f()); // 输出: 1 printf("%d\n", f()); // 输出: 2 return 0; } ``` 内嵌函数增强了代码模块化,但需注意可移植性问题(仅 GCC 支持)[^3]。 #### 6. **其他扩展功能** - **内建数学函数**:如 `__builtin_sin(x)` 直接调用硬件加速的数学函数,比标准库更高效。 - **向量扩展**:支持 SIMD 指令(如 SSE/AVX),通过 `__attribute__((vector_size(N)))` 定义向量类型。 - **溢出检查函数**:如 `__builtin_add_overflow(a, b, &result)` 检测算术溢出。 - **预处理扩展**:GCC 提供标准预定义宏(如 `__GNUC__` 检测 GCC 版本),用于条件编译[^2]。 #### 总结 GCC 的扩展功能(如属性、内联汇编、原子操作和内嵌函数)显著增强了 C/C++ 的灵活性和性能,尤其在系统编程、并发控制和优化中不可或缺。然而,这些扩展可能降低代码可移植性(依赖 GCC),建议仅在必要时使用,并参考 [GCC 官方文档](https://gcc.gnu.org/onlinedocs/) 确保兼容性[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值