Gcc内置原子操作

介绍

Gcc 4.1.2版本之后,对X86或X86_64支持内置原子操作。就是说,不需要引入第三方库(如pthread)的锁保护,即可对1、2、4、8字节的数值或指针类型,进行原子加/减/与/或/异或等操作。

接口介绍

接口说明
__sync_synchronize内存访问栅,确保所有对内存的操作都完成,防止乱序执行
__sync_fetch_and_add(ptr, 0)原子获取操作,获取指针 ptr 指向的内存值
__sync_lock_test_and_set((ptr), (value))原子设置操作,如果原值和新值不一样,则设置新值
((typeof(*(ptr)))__sync_lock_test_and_set((ptr), (value)))原子交换操作,如果被设置,则返回旧值,否则返回设置值
((typeof(*(ptr)))__sync_val_compare_and_swap((ptr), (comp), (value)))原子比较交换操作,如果当前值等于旧值,则设置新值,并返回旧值,否则返回新值
(__sync_bool_compare_and_swap((ptr), (comp), (value)) != 0 ? true : false)原子比较交换操作,如果当前值等于旧值,则设置新值,返回真值,否则返回假
((void)__sync_lock_release((ptr)))原子清零操作,将指针 ptr 指向的内存值设置为0
((typeof(*(ptr)))__sync_add_and_fetch((ptr), (value)))算数运算加value,返回新值
((typeof(*(ptr)))__sync_sub_and_fetch((ptr), (value)))算数运算减value,返回新值
((typeof(*(ptr)))__sync_or_and_fetch((ptr), (value)))算数运算与value相或,返回新值
((typeof(*(ptr)))__sync_and_and_fetch((ptr), (value)))算数运算与value相与,返回新值
((typeof(*(ptr)))__sync_xor_and_fetch((ptr), (value)))算数运算与value相异或,返回新值
((typeof(*(ptr)))__sync_fetch_and_add((ptr), (value)))算数运算加value,返回减之前的值
((typeof(*(ptr)))__sync_fetch_and_sub((ptr), (value)))算数运算减value,返回减之前的值
((typeof(*(ptr)))__sync_fetch_and_or((ptr), (value)))算数运算与value相或,返回操作之前的值
((typeof(*(ptr)))__sync_fetch_and_and((ptr), (value)))算数运算与value相与,返回操作之前的值
((typeof(*(ptr)))__sync_fetch_and_xor((ptr), (value)))算数运算与value相异或,返回操作之前的值
((void)xrte_atomic_add_f((ptr), 1))原子递增操作,将指针 ptr 指向的内存值加1
((void)xrte_atomic_sub_f((ptr), 1))原子递减操作,将指针 ptr 指向的内存值减1
((void)xrte_atomic_add_f((ptr), (val)))原子增加操作,将指针 ptr 指向的内存值增加 val
((void)xrte_atomic_sub_f((ptr), (val)))原子减少操作,将指针 ptr 指向的内存值减少 val
((void)xrte_atomic_or_f((ptr), (val)))原子按位或操作,将指针 ptr 指向的内存值与 val 按位或
((void)xrte_atomic_and_f((ptr), (val)))原子按位与操作,将指针 ptr 指向的内存值与 val 按位与
((void)xrte_atomic_xor_f((ptr), (val)))原子按位异或操作,将指针 ptr 指向的内存值与 val 按位异或

例子

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
int g_iFlagAtom = 1;
#define WORK_SIZE 5000000
#define WORKER_COUNT 10
pthread_t g_tWorkerID[WORKER_COUNT];
int g_iSum = 0;
 
void * thr_worker(void *arg) {
   printf ("WORKER THREAD %08X STARTUP\n", (unsigned int)pthread_self());
   int i=0;
   for (i=0; i<WORK_SIZE; ++i) {
       if (g_iFlagAtom) {
           __sync_fetch_and_add(&g_iSum, 1);
       } else {
           g_iSum ++;
       }
   }
   return NULL;
}
 
void * thr_management (void *arg) {
   printf ("MANAGEMENT THREAD %08X STARTUP\n", (unsigned int)pthread_self());
   int i;
   for (i=0;i<WORKER_COUNT;++i) {
       pthread_join(g_tWorkerID[i], NULL);
   }
   printf ("ALL WORKER THREADS FINISHED.\n");
   return NULL;
}
 
int main(int argc, const char* argv[]) {
   pthread_t tManagementID;
   pthread_create (&tManagementID, NULL, thr_management, NULL);
   int i=0; 
   for (i=0;i<WORKER_COUNT;++i) {
       pthread_create(&g_tWorkerID[i], NULL, thr_worker, NULL);
   }
   printf ("CREATED %d WORKER THREADS\n", i);
   pthread_join(tManagementID, NULL);
   printf ("THE SUM: %d\n", g_iSum);
   return 0;
}

__sync_synchronize

__sync_synchronize是一个GCC内置函数,用于实现同步操作。它的作用是强制对内存的修改操作进行同步,确保所有之前的修改都被提交并对其他线程可见。具体而言, __sync_synchronize 函数会生成一个完整的内存栅栏(memory barrier),防止编译器和处理器对内存操作进行重排或优化。

在多线程编程中, __sync_synchronize 函数通常用于实现原子操作,即确保对共享变量的操作是原子性的、不可分割的。通过在关键位置调用 __sync_synchronize 函数,可以保证线程间的数据同步和一致性。

需要注意的是, __sync_synchronize 函数在C11标准中已被弃用,推荐使用 <stdatomic.h> 头文件中的原子操作函数来替代。

#include <stdio.h>

int shared_var = 0;

void* thread_function(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        // 在这里进行一些操作,例如递增共享变量
        shared_var++;
        
        // 在操作完成后调用 __sync_synchronize 函数进行同步
        __sync_synchronize();
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    
    // 创建两个线程来同时操作共享变量
    pthread_create(&thread1, NULL, thread_function, NULL);
    pthread_create(&thread2, NULL, thread_function, NULL);
    
    // 等待两个线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    // 输出最终的共享变量值
    printf("shared_var = %d\n", shared_var);
    
    return 0;
}
原子操作是指一个不可分割的操作,要么全部执行,要么全部不执行,不会出现部分执行的情况,也不会被其他线程干扰或打断。在多线程并发环境中,原子操作是保证数据同步和线程安全的一种重要机制。 在C语言中,可以使用GCC提供的内置函数来实现原子操作。其中,`__sync_fetch_and_add()`函数用于实现原子加法操作,`__sync_fetch_and_sub()`函数用于实现原子减法操作,`__sync_fetch_and_or()`函数用于实现原子按位或操作,`__sync_fetch_and_and()`函数用于实现原子按位与操作,`__sync_fetch_and_xor()`函数用于实现原子按位异或操作等。 下面是一个使用`__sync_fetch_and_add()`函数实现原子加法操作的例子: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> int counter = 0; // 全局计数器 void *thread_func(void *arg) { int i; for (i = 0; i < 1000000; i++) { __sync_fetch_and_add(&counter, 1); // 原子加1操作 } return NULL; } int main() { pthread_t thread1, thread2; pthread_create(&thread1, NULL, thread_func, NULL); pthread_create(&thread2, NULL, thread_func, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); printf("counter = %d\n", counter); // 输出计数器的值 return 0; } ``` 在上面的例子中,首先定义了一个全局计数器`counter`,然后创建了两个线程,每个线程执行1000000次的原子加1操作。最后,输出计数器的值。 需要注意的是,在进行原子操作时,需要考虑内存对齐和缓存一致性等问题,以避免出现数据竞争和冲突。同时,原子操作的实现也需要考虑硬件架构和操作系统环境等因素的影响。因此,在使用原子操作时,建议使用标准库或第三方库提供的封装好的原子操作函数,以保证正确性和可移植性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起风就扬帆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值