C语言_Atomic类型限定符

并发程序设计把程序执行分成可以同时执行的多个线程。这程序设计带来了新的挑战,包括如何管理访问相同数据的不同线程。C11通过包含可选的头文件stdatomic.h和threads.h,提供了一些可选的(不是必须实现的)管理方法。值得注意的是,要通过各种红函数类访问原子类型。当一个线程对一个原子类型的对象执行原子操作时,其他线程不能访问该对象。

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。

所以这里说到的原子操作,基本都包含我们三个方面所关心的语义:操作本身是不可分割的(Atomicity),一个线程对某个数据的操作何时对另外一个线程可见(Visibility),执行的顺序是否可以被重排(Ordering)。

这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。

用_Atomic(类型名)这种方式修饰的类型是原子类型,在实际使用原子类型时应当避免直接使用_Atomic(类型名)这种形式,而是直接用<stdatomic.h>头文件中已经定义好的原子类型。此外该头文件还有相应的原子操作函数。

常用的原子类型

typedef _Atomic _Bool atomic_bool;
typedef _Atomic char atomic_char;
typedef _Atomic signed char atomic_schar;
typedef _Atomic unsigned char atomic_uchar;
typedef _Atomic short atomic_short;
typedef _Atomic unsigned short atomic_ushort;
typedef _Atomic int atomic_int;
typedef _Atomic unsigned int atomic_uint;
typedef _Atomic long atomic_long;
typedef _Atomic unsigned long atomic_ulong;
typedef _Atomic long long atomic_llong;
typedef _Atomic unsigned long long atomic_ullong;
...

声明示例如:

_Atomic const int * p1;  // p is a pointer to an atomic const int
const atomic_int * p2;   // same
const _Atomic(int) * p3; // same

常用的原子操作函数

atomic_init 初始化
atomic_store 赋值
atomic_load 获取
atomic_fetch_add 加
atomic_fetch_sub 减
...

 

//单线程示例
#include <stdio.h>
#include <stdatomic.h>

atomic_int atomic_count = ATOMIC_VAR_INIT(1);

void test()
{
    atomic_int a;
    atomic_init(&a,10);
    int* a_ptr = (int *) &a;
    atomic_store(a_ptr,20);
    int b = atomic_load(a_ptr);
    printf("b = %d\n",b);
    int* atomic_count_ptr = (int *) &atomic_count;
    int atomic_count_old_value = atomic_fetch_add(atomic_count_ptr,b);
    printf("atomic_count_old_value = %d\n",atomic_count_old_value);
    int int_atomic_count = atomic_load(atomic_count_ptr);
    printf("atomic_count = %d\n",int_atomic_count);
}

int main(void)
{
    test();
    return 0;
}

 

//多线程示例
#include <stdio.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>

static volatile atomic_ullong sAtomResult = ATOMIC_VAR_INIT(0);
static volatile atomic_int sAtomIndex = ATOMIC_VAR_INIT(0);
static volatile uint64_t sNormalResult = 0;
static volatile int sNormalIndex = 0;
static volatile bool sIsThreadComplete = false;
static int sArray[10000][100];

static void* NormalSumProc(void *param) {
    int currIndex;
    while((currIndex = sNormalIndex++) < 10000) {
        uint64_t sum = 0;
        for (int i = 0;i < 100; i++) {
            sum += sArray[currIndex][i];
        }
        sNormalResult += sum;
    }
    sIsThreadComplete = true;
    return NULL;
}

static void* AtomSumProc(void *param) {
    int currIndex;

    while((currIndex = atomic_fetch_add(&sAtomIndex,1))<10000) {
        uint64_t sum = 0;
        for (int i = 0; i < 100; ++i) {
            sum += sArray[currIndex][i];
        }
        atomic_fetch_add(&sAtomResult,sum);
    }
    sIsThreadComplete = true;
    return NULL;
}

int main(int argc,const char* argv[]){
    for (int i = 0; i < 10000; ++i) {
        for (int j = 0; j < 100; ++j) {
            sArray[i][j] = 100 * i + j;
        }
    }
    unsigned long long standardResult = 0;
    for (int i = 0; i < 10000; ++i) {
        for (int j = 0; j < 100; ++j) {
            standardResult += sArray[i][j];
        }
    }
    printf("The standard result is %llu\n",standardResult);

    pthread_t pthreadID;
    pthread_t threadID;
    pthread_create(&threadID,NULL,&NormalSumProc,NULL);

    int currIndex;
    while((currIndex = sNormalIndex++)<10000){
        uint64_t sum = 0;
        for (int i = 0; i < 100; ++i) {
            sum += sArray[currIndex][i];
        }
        sNormalResult += sum;
    }
    while(!sIsThreadComplete);
    if (sNormalResult == standardResult) {
        puts("Normal compute compared equal!");
    } else {
        printf("Normal compute compared not equal: %lu\n",sNormalResult);
    }
    sIsThreadComplete = false;
    pthread_create(&threadID,NULL,&AtomSumProc,NULL);
    while((currIndex = atomic_fetch_add(&sAtomIndex,1))<10000){
        uint64_t sum = 0;
        for (int i = 0; i < 100; ++i) {
            sum += sArray[currIndex][i];
        }
        atomic_fetch_add(&sAtomResult,sum);
    }
    while(!sIsThreadComplete);
    if (atomic_load(&sAtomResult) == standardResult) {
        puts("Atom compute compared equal!");
    } else {
        puts("Atom compute compared not equal!");
    }
}



原文链接:

1. https://stackoverflow.com/questions/26463074/is-there-a-difference-between-the-atomic-type-qualifier-and-type-specifier

2. https://blog.csdn.net/Galaxy_Robot/article/details/106991200

3.史蒂芬・普拉达. C Primer Plus (第6版) 中文版[M]. 人民邮电出版社, 2016.

4.atomic_inc 原子操作

5.C++11 并发指南(atomic 类型详解四 C 风格原子操作介绍)

6。https://www.cnblogs.com/embedded-linux/p/5577901.html

7. 原子操作 library

8. Atomic types

 

posted @   星辰大海浩瀚宇宙呀  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示