成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux環(huán)境多線程編程基礎(chǔ)設(shè)施

系統(tǒng) Linux
本文介紹多線程環(huán)境下并行編程的基礎(chǔ)設(shè)施。

本文介紹多線程環(huán)境下并行編程的基礎(chǔ)設(shè)施。主要包括:

  • volatile
  • __thread
  • Memory Barrier
  • __sync_synchronize

volatile

編譯器有時(shí)候?yàn)榱藘?yōu)化性能,會(huì)將一些變量的值緩存到寄存器中,因此如果編譯器發(fā)現(xiàn)該變量的值沒有改變的話,將從寄存器里讀出該值,這樣可以避免內(nèi)存訪問。

但是這種做法有時(shí)候會(huì)有問題。如果該變量確實(shí)(以某種很難檢測(cè)的方式)被修改呢?那豈不是讀到錯(cuò)的值?是的。在多線程情況下,問題更為突出:當(dāng)某個(gè)線程對(duì)一個(gè)內(nèi)存單元進(jìn)行修改后,其他線程如果從寄存器里讀取該變量可能讀到老值,未更新的值,錯(cuò)誤的值,不新鮮的值。

如何防止這樣錯(cuò)誤的“優(yōu)化”?方法就是給變量加上volatile修飾。

  1. volatile int i=10;//用volatile修飾變量i 
  2.  
  3. ......//something happened 
  4.  
  5. int b = i;//強(qiáng)制從內(nèi)存中讀取實(shí)時(shí)的i的值  

OK,畢竟volatile不是完美的,它也在某種程度上限制了優(yōu)化。有時(shí)候是不是有這樣的需求:我要你立即實(shí)時(shí)讀取數(shù)據(jù)的時(shí)候,你就訪問內(nèi)存,別優(yōu)化;否則,你該優(yōu)化還是優(yōu)化你的。能做到嗎?

不加volatile修飾,那么就做不到前面一點(diǎn)。加了volatile,后面這一方面就無從談起,怎么辦?傷腦筋。

其實(shí)我們可以這樣:

  1. int i = 2; //變量i還是不用加volatile修飾 
  2.  
  3. #define ACCESS_ONCE(x) (* (volatile typeof(x) *) &(x))  

需要實(shí)時(shí)讀取i的值時(shí)候,就調(diào)用ACCESS_ONCE(i),否則直接使用i即可。

這個(gè)技巧,我是從《Is parallel programming hard?》上學(xué)到的。

聽起來都很好?然而險(xiǎn)象環(huán)生:volatile常被誤用,很多人往往不知道或者忽略它的兩個(gè)特點(diǎn):在C/C++語言里,volatile不保證原子性;使用volatile不應(yīng)該對(duì)它有任何Memory Barrier的期待。

第一點(diǎn)比較好理解,對(duì)于第二點(diǎn),我們來看一個(gè)很經(jīng)典的例子:

  1. volatile int is_ready = 0; 
  2.  
  3. char message[123]; 
  4.  
  5. void thread_A 
  6.  
  7.  
  8.   while(is_ready == 0) 
  9.  
  10.   { 
  11.  
  12.   } 
  13.  
  14.   //use message; 
  15.  
  16.  
  17. void thread_B 
  18.  
  19.  
  20.   strcpy(message,"everything seems ok"); 
  21.  
  22.   is_ready = 1; 
  23.  
  24.  

線程B中,雖然is_ready有volatile修飾,但是這里的volatile不提供任何Memory Barrier,因此12行和13行可能被亂序執(zhí)行,is_ready = 1被執(zhí)行,而message還未被正確設(shè)置,導(dǎo)致線程A讀到錯(cuò)誤的值。

這意味著,在多線程中使用volatile需要非常謹(jǐn)慎、小心。

__thread

__thread是gcc內(nèi)置的用于多線程編程的基礎(chǔ)設(shè)施。用__thread修飾的變量,每個(gè)線程都擁有一份實(shí)體,相互獨(dú)立,互不干擾。舉個(gè)例子:

  1. #include 
  2.  
  3. #include 
  4.  
  5. #include 
  6.  
  7. using namespace std; 
  8.  
  9. __thread int i = 1; 
  10.  
  11. void* thread1(void* arg); 
  12.  
  13. void* thread2(void* arg); 
  14.  
  15. int main() 
  16.  
  17.  
  18.   pthread_t pthread1; 
  19.  
  20.   pthread_t pthread2; 
  21.  
  22.   pthread_create(&pthread1, NULL, thread1, NULL); 
  23.  
  24.   pthread_create(&pthread2, NULL, thread2, NULL); 
  25.  
  26.   pthread_join(pthread1, NULL); 
  27.  
  28.   pthread_join(pthread2, NULL); 
  29.  
  30.   return 0; 
  31.  
  32.  
  33. void* thread1(void* arg) 
  34.  
  35.  
  36.   coutiendl;//輸出 2   
  37.  
  38.   return NULL
  39.  
  40.  
  41. void* thread2(void* arg) 
  42.  
  43.  
  44.   sleep(1); //等待thread1完成更新 
  45.  
  46.   coutiendl;//輸出 2,而不是3 
  47.  
  48.   return NULL
  49.  
  50.  

需要注意的是:

1,__thread可以修飾全局變量、函數(shù)的靜態(tài)變量,但是無法修飾函數(shù)的局部變量。

2,被__thread修飾的變量只能在編譯期初始化,且只能通過常量表達(dá)式來初始化。

Memory Barrier

為了優(yōu)化,現(xiàn)代編譯器和CPU可能會(huì)亂序執(zhí)行指令。例如:

  1. int a = 1; 
  2.  
  3. int b = 2; 
  4.  
  5. a = b + 3; 
  6.  
  7. b = 10;  

CPU亂序執(zhí)行后,第4行語句和第5行語句的執(zhí)行順序可能變?yōu)橄萣=10然后再a=b+3

有些人可能會(huì)說,那結(jié)果不就不對(duì)了嗎?b為10,a為13?可是正確結(jié)果應(yīng)該是a為5啊。

哦,這里說的是語句的執(zhí)行,對(duì)應(yīng)的匯編指令不是簡(jiǎn)單的mov b,10和mov b,a+3。

生成的匯編代碼可能是:

  1. movl    b(%rip), %eax ; 將b的值暫存入%eax 
  2.  
  3. movl    $10, b(%rip) ; b = 10 
  4.  
  5. addl    $3, %eax ; %eax加3 
  6.  
  7. movl    %eax, a(%rip) ; 將%eax也就是b+3的值寫入a,即 a = b + 3  

這并不奇怪,為了優(yōu)化性能,有時(shí)候確實(shí)可以這么做。但是在多線程并行編程中,有時(shí)候亂序就會(huì)出問題。

一個(gè)最典型的例子是用鎖保護(hù)臨界區(qū)。如果臨界區(qū)的代碼被拉到加鎖前或者釋放鎖之后執(zhí)行,那么將導(dǎo)致不明確的結(jié)果,往往讓人不開心的結(jié)果。

還有,比如隨意將讀數(shù)據(jù)和寫數(shù)據(jù)亂序,那么本來是先讀后寫,變成先寫后讀就導(dǎo)致后面讀到了臟的數(shù)據(jù)。因此,Memory Barrier就是用來防止亂序執(zhí)行的。具體說來,Memory Barrier包括三種:

1,acquire barrier。acquire barrier之后的指令不能也不會(huì)被拉到該acquire barrier之前執(zhí)行。

2,release barrier。release barrier之前的指令不能也不會(huì)被拉到該release barrier之后執(zhí)行。

3,full barrier。以上兩種的合集。

所以,很容易知道,加鎖,也就是lock對(duì)應(yīng)acquire barrier;釋放鎖,也就是unlock對(duì)應(yīng)release barrier。哦,那么full barrier呢?

__sync_synchronize

__sync_synchronize就是一種full barrier。 

責(zé)任編輯:龐桂玉 來源: 程序源
相關(guān)推薦

2009-12-18 17:14:25

惠普基礎(chǔ)架構(gòu)

2009-12-22 13:59:59

惠普基礎(chǔ)設(shè)施運(yùn)營(yíng)

2022-02-10 11:54:34

即時(shí)基礎(chǔ)設(shè)施基礎(chǔ)設(shè)施數(shù)字化轉(zhuǎn)型

2023-07-17 18:43:26

測(cè)試基礎(chǔ)設(shè)施開發(fā)

2017-09-16 17:28:55

基礎(chǔ)設(shè)施代碼持續(xù)交付

2020-04-09 10:57:12

超融合基礎(chǔ)設(shè)施服務(wù)器超融合

2023-06-16 15:53:55

DevOps基礎(chǔ)設(shè)施

2023-08-04 16:32:18

2021-05-08 13:13:55

智能設(shè)施漏洞攻擊

2009-03-12 10:52:43

Java線程多線程

2020-02-24 11:08:27

云計(jì)算網(wǎng)絡(luò)攻擊數(shù)據(jù)

2022-04-06 15:04:28

網(wǎng)絡(luò)安全基礎(chǔ)設(shè)施

2020-04-28 10:21:58

基礎(chǔ)設(shè)施硬件遠(yuǎn)程工作

2015-12-07 09:39:53

光纖數(shù)據(jù)中心

2017-06-09 15:25:23

IT設(shè)施數(shù)據(jù)中心融合

2024-09-30 11:29:07

2013-08-01 09:12:41

企業(yè)基礎(chǔ)設(shè)施虛擬化網(wǎng)絡(luò)設(shè)備

2021-08-11 09:18:17

能源物聯(lián)網(wǎng)應(yīng)用物聯(lián)網(wǎng)

2015-05-27 09:03:46

IT基礎(chǔ)設(shè)施IT基礎(chǔ)設(shè)施監(jiān)控

2012-02-08 13:48:32

存儲(chǔ)公有云
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 56pao在线| 日韩在线成人 | 欧美精品一区二区在线观看 | 欧美激情一区二区三级高清视频 | 午夜电影网 | 毛片一区二区三区 | 黄色国产在线播放 | 精品久久一区二区三区 | 国产精品久久久久久久免费观看 | 中文天堂在线一区 | 四虎av电影 | 精品国产乱码一区二区三区a | 夜夜骑天天干 | 精品国产一区二区三区久久影院 | 成人在线视频一区 | 国产资源一区二区三区 | 亚洲午夜av久久乱码 | 中文字幕在线观看一区二区 | 久久国产一区二区 | 一本一道久久a久久精品蜜桃 | av免费电影在线 | 国产一级一级毛片 | 国产精品观看 | 黄色毛片免费视频 | 91电影 | 国产一二区视频 | 国产精品视频网站 | 成人免费观看视频 | 嫩草国产 | 一区二区精品 | 久久久久久黄 | 日韩色图视频 | 日韩视频在线免费观看 | 欧洲亚洲精品久久久久 | 视频在线一区二区 | 久久成人一区 | 福利精品在线观看 | 亚洲视频一区二区 | 密室大逃脱第六季大神版在线观看 | 色婷婷久久综合 | 国产毛片久久久久久久久春天 |