第4章 原子操作
发布日期:2021-06-30 18:59:10 浏览次数:2 分类:技术文章

本文共 1980 字,大约阅读时间需要 6 分钟。

有一件事情,你不得不承认,C语言相对汇编来说是高级语言,为什么,因为高级语言会形成封装,比如,我需要把一个变量A++,对于CPU来说,先从内存里把这个变量读进运算寄存器,然后运算增加,然后再把A写入原来的内存位置。

什么是原子操作?

不被其他事件打断的操作,就叫做原子操作。

老外是用这样一句话来说明这个

“Do this, and don’t get interrupted while doing this.”

我们在CPU里面,想把A++,执行一次,因为是C语言实现的,所以这个指令会被编译成汇编语言,变成了好几个指令,比如CPU从内存中拿A到寄存器里面,这个操作,就可能被其他事件打断,有可能是中断,也可能是定时器,也有可能是CPU线程调度等其他原因。

为什么我们要讨论原子操作?

如果没有多线程编程的同学,应该对这个没概念,也不会知道这个会引起什么问题,这样好了,我来写一个例子。

 
#include 
#include
#include
#include
#include
#define gettidv1() syscall(__NR_gettid) #define gettidv2() syscall(SYS_gettid) long int NUM = 0; void * th(void * ptr) { int i = 0; for(i = 0;i < 1000000000;i++) { NUM++; } //sleep(1); //printf("IM %s ID:%ld number:%ld\n",(char*)ptr,gettidv1(),NUM); } int main(int argc,char ** argv) { pthread_t thread1 = -1; if(pthread_create(&thread1,NULL,th,"th1")!=0) { printf("thread1 creat error\n"); } pthread_t thread2 = -1; if(pthread_create(&thread2,NULL,th,"th2")!=0) { printf("thread1 creat error\n"); } while(1) { printf("IM %s ID:%ld number:%ld\n","Main",gettidv1(),NUM); sleep(2); }; }

Makefile文件

 
all:	  gcc thread.c -o thread -pthread	clean:	  rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
 

输出结果

 
linux@ubuntu:~/linuxBook/linux-c/pthread$ make && ./thread	gcc thread.c -o thread -pthread	IM Main ID:7503 number:0	IM Main ID:7503 number:638925977	IM Main ID:7503 number:1334751130	IM Main ID:7503 number:1997474779
 

总结下原因

我相信很多人应该看过类似的例子,但是可能没有自己去写过,而且可能写的时候,给的变量比较小,就有可能导致看到的结果不一样。

我说下原因,因为NUM++ ,这个操作不是原子的,就是说他在干活的时候,有可能被其他东西打断。

640?wx_fmt=png

线程1在执行第一步的时候,CPU的控制器被调度给线程2使用了,然后呢,线程2 就做自己的事情,把NUM运算成1了,然后CPU控制权又回来到线程1这里,因为线程1刚才上一次的运算还没有完成,他就继续用原来寄存器里面的数据进行运算,然后NUM最后还是1。

可以看到一个问题的是,线程2的这次操作被忽略了,实际上他打工干活了,但是包工头没有给他记账,结果后面结账的时候,也没有给他工钱,这个就比较悲剧了。

在单核CPU上应该很好理解,但是在多核上要费点心思,SMP加上L1,L2缓存后,处理变得很复杂。

之前文章有点长,以后还是简化文章,觉得不错,支持一下。

640?wx_fmt=jpeg

转载地址:https://linus.blog.csdn.net/article/details/97622108 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:随笔日记
下一篇:别人不让你发传单怎么办?

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月08日 14时31分46秒