原子操作概述
有一件事情,你不得不承認(rèn),C語(yǔ)言相對(duì)匯編來說是高級(jí)語(yǔ)言,為什么,因?yàn)楦呒?jí)語(yǔ)言會(huì)形成封裝,比如,我需要把一個(gè)變量A++,對(duì)于CPU來說,先從內(nèi)存里把這個(gè)變量讀進(jìn)運(yùn)算寄存器,然后運(yùn)算增加,然后再把A寫入原來的內(nèi)存位置。
?
什么是原子操作?
不被其他事件打斷的操作,就叫做原子操作。
老外是用這樣一句話來說明這個(gè)
“Do this, and don’t get interrupted while doing this.”
?
我們?cè)贑PU里面,想把A++,執(zhí)行一次,因?yàn)槭荂語(yǔ)言實(shí)現(xiàn)的,所以這個(gè)指令會(huì)被編譯成匯編語(yǔ)言,變成了好幾個(gè)指令,比如CPU從內(nèi)存中拿A到寄存器里面,這個(gè)操作,就可能被其他事件打斷,有可能是中斷,也可能是定時(shí)器,也有可能是CPU線程調(diào)度等其他原因。
為什么我們要討論原子操作?
如果沒有多線程編程的同學(xué),應(yīng)該對(duì)這個(gè)沒概念,也不會(huì)知道這個(gè)會(huì)引起什么問題,這樣好了,我來寫一個(gè)例子。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <sys/syscall.h> #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輸出結(jié)果
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?
總結(jié)下原因
我相信很多人應(yīng)該看過類似的例子,但是可能沒有自己去寫過,而且可能寫的時(shí)候,給的變量比較小,就有可能導(dǎo)致看到的結(jié)果不一樣。
我說下原因,因?yàn)镹UM++ ,這個(gè)操作不是原子的,就是說他在干活的時(shí)候,有可能被其他東西打斷。
?
線程1在執(zhí)行第一步的時(shí)候,CPU的控制器被調(diào)度給線程2使用了,然后呢,線程2 就做自己的事情,把NUM運(yùn)算成1了,然后CPU控制權(quán)又回來到線程1這里,因?yàn)榫€程1剛才上一次的運(yùn)算還沒有完成,他就繼續(xù)用原來寄存器里面的數(shù)據(jù)進(jìn)行運(yùn)算,然后NUM最后還是1。
可以看到一個(gè)問題的是,線程2的這次操作被忽略了,實(shí)際上他打工干活了,但是包工頭沒有給他記賬,結(jié)果后面結(jié)賬的時(shí)候,也沒有給他工錢,這個(gè)就比較悲劇了。
在單核CPU上應(yīng)該很好理解,但是在多核上要費(fèi)點(diǎn)心思,SMP加上L1,L2緩存后,處理變得很復(fù)雜。
之前文章有點(diǎn)長(zhǎng),以后還是簡(jiǎn)化文章,覺得不錯(cuò),支持一下。
總結(jié)
 
                            
                        - 上一篇: 记录不认识的英文单词
- 下一篇: 头文件的查找方式和库的搜索路径
