<em id="pn7p8"><acronym id="pn7p8"><u id="pn7p8"></u></acronym></em>

    <th id="pn7p8"></th>

    <button id="pn7p8"></button>

      <dd id="pn7p8"></dd>
      <progress id="pn7p8"><track id="pn7p8"></track></progress>

      Linux培訓
      達內IT學院

      400-111-8989

      Linux環境多線程編程基礎設施

      • 發布:Linux培訓
      • 來源:Linux教程
      • 時間:2016-08-10 14:23

      編譯器有時為優化性能,會將一些變量的值緩存到寄存器中。因此,如果編譯器發現該變量的值沒有改變,將從寄存器里讀出該值,這樣可以避免內存訪問。

      如果該變量確實被修改了呢?那豈不是讀到錯的值了嗎?

      是的。在多線程情況下,問題更為突出:

      當某個線程對一個內存單元進行修改后,其他線程如果從寄存器里讀取該變量可能讀到老值,未更新的值,錯誤的值,不新鮮的值。

      如何防止這樣錯誤的“優化”?方法就是給變量加上volatile修飾。

      volatile int i=10;//用volatile修飾變量i......//something happened int b = i;//強制從內存中讀取實時的i的值

      OK,畢竟volatile不是完美的,它也在某種程度上限制了優化。

      有時候是不是有這樣的需求:我要你立即實時讀取數據的時候,你就訪問內存,別優化;否則,你該優化還是優化。能做到嗎?

      不加volatile修飾,那么就做不到前面一點。加了volatile,后面這一方面就無從談起,怎么辦?

      其實我們可以這樣:

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

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

      聽起來很好,然而險象環生:

      volatile常被誤用,很多人往往不知道或者忽略它的兩個特點:

      在C/C++語言里,volatile不保證原子性;

      使用volatile不應該對它有任何Memory Barrier的期待。

      第一點比較好理解,對于第二點,我們來看一個很經典的例子:

      volatile int is_ready = 0;char message[123];void thread_A
      {  while(is_ready == 0)
        {
        }  //use message;}void thread_B
      {  strcpy(message,"everything seems ok");
        is_ready = 1;
      }

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

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

      __thread

      __thread是gcc內置的用于多線程編程的基礎設施。用__thread修飾的變量,每個線程都擁有一份實體,相互獨立,互不干擾。舉個例子:

      #include<iostream>  #include<pthread.h>  #include<unistd.h>  using namespace std;
      __thread int i = 1;void* thread1(void* arg);void* thread2(void* arg);int main(){  pthread_t pthread1;  pthread_t pthread2;
        pthread_create(&pthread1, NULL, thread1, NULL);
        pthread_create(&pthread2, NULL, thread2, NULL);
        pthread_join(pthread1, NULL);
        pthread_join(pthread2, NULL);  return 0;
      }void* thread1(void* arg){  cout<<++i<<endl;//輸出 2  
        return NULL;
      }void* thread2(void* arg){
        sleep(1); //等待thread1完成更新
        cout<<++i<<endl;//輸出 2,而不是3
        return NULL;
      }

      需要注意的是:

      1. __thread可以修飾全局變量、函數的靜態變量,但是無法修飾函數的局部變量。

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

      Memory Barrier

      為了優化,現代編譯器和CPU可能會亂序執行指令。例如:

      int a = 1;int b = 2;a = b + 3;b = 10;

      CPU亂序執行后,第4行語句和第5行語句的執行順序可能變為先b=10然后再a=b+3

      有些人可能會說,那結果不就不對了嗎?b為10,a為13?可是正確結果應該是a為5啊。

      這里說的是語句的執行,對應的匯編指令不是簡單的mov b,10和mov b,a+3。

      生成的匯編代碼可能是:

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

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

      一個最典型的例子是用鎖保護臨界區。如果臨界區的代碼被拉到加鎖前或者釋放鎖之后執行,那么將導致不明確的結果。

      還有,比如隨意將讀數據和寫數據亂序,那么本來是先讀后寫,變成先寫后讀就導致后面讀到了臟的數據。

      因此,Memory Barrier就是用來防止亂序執行的。具體說來,Memory Barrier包括三種:

      1. acquire barrier。acquire barrier之后的指令不能被拉到該acquire barrier之前執行。

      2. release barrier。release barrier之前的指令不能被拉到該release barrier之后執行。

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

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

      __sync_synchronize

      __sync_synchronize就是一種full barrier。

      預約申請免費試聽課

      填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

      上一篇:linux常用命令
      下一篇:Linux進程調度
      • 掃碼領取資料

        回復關鍵字:視頻資料

        免費領取 達內課程視頻學習資料

      • 視頻學習QQ群

        添加QQ群:1143617948

        免費領取達內課程視頻學習資料

      Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

      選擇城市和中心
      黑龍江省

      吉林省

      河北省

      湖南省

      貴州省

      云南省

      廣西省

      海南省

      高清特黄a大片,日本真人真做爰,特级做人爱C级,免费a级毛片 百度 好搜 搜狗
      <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>