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.
5.C++11 并发指南(atomic 类型详解四 C 风格原子操作介绍)
6。https://www.cnblogs.com/embedded-linux/p/5577901.html
7. 原子操作 library
8. Atomic types
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理