<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      拾貝雜苑

      Linux/Unix 線程同步技術之互斥量(1)

      眾所周知,互斥量(mutex)是同步線程對共享資源訪問的技術,用來防止下面這種情況:線程A試圖訪問某個共享資源時,線程B正在對其進行修改,從而造成資源狀態不一致。與之相關的一個術語臨界區(critical section)是指訪問某一共享資源的代碼片段,并且這段代碼的執行為原子(atomic)操作,即同時訪問同一共享資源的其他線程不應中斷該片段的執行。

      我們先來看看不使用臨界區技術保護共享資源的例子,該例子使用2個線程來同時遞增同一個全局變量。

      代碼示例1:不使用臨界區技術訪問共享資源

       1 #include <pthread.h>
       2 #include <stdio.h>
       3 #include <stdlib.h>
       4 
       5 static int g_n = 0;
       6 
       7 static void *
       8 thread_routine(void *arg)
       9 {
      10     int n_loops = (int)(arg);
      11     int loc;
      12     int j;
      13     
      14     for (j = 0; j < n_loops; j++)
      15     {
      16         loc = g_n;
      17         loc++;
      18         g_n = loc;
      19     }
      20     
      21     return 0;
      22 }
      23 
      24 int
      25 main(int argc, char *argv[])
      26 {
      27     int n_loops, s;
      28     pthread_t t1, t2;
      29     void *args[2];
      30     
      31     n_loops = (argc > 1) ? atoi(argv[1]) : 10000000;
      32     
      33     args[0] = (void *)n_loops;
      34     s = pthread_create(&t1, 0, thread_routine, &args);
      35     if (s != 0)
      36     {
      37         perror("error pthread_create.\n");
      38         exit(EXIT_FAILURE);
      39     }
      40     
      41     s = pthread_create(&t2, 0, thread_routine, &args);
      42     if (s != 0)
      43     {
      44         perror("error pthread_create.\n");
      45         exit(EXIT_FAILURE);
      46     }
      47     
      48     s = pthread_join(t1, 0);
      49     if (s != 0)
      50     {
      51         perror("error pthread_join.\n");
      52         exit(EXIT_FAILURE);
      53     }
      54     
      55     s = pthread_join(t2, 0);
      56     if (s != 0)
      57     {
      58         perror("error pthread_join.\n");
      59         exit(EXIT_FAILURE);
      60     }
      61 
      62     printf("Loops [%d] times by 2 threads without critical section.\n", n_loops);
      63     printf("Var g_n is [%d].\n", g_n);
      64     exit(EXIT_SUCCESS);
      65 }

      運行以上代碼生成的程序,若循環次數較少,比如每個線程都對全局變量g_n遞增1000次,結果看起來很正常:

      $ ./thdincr_nosync 1000
      Loops [1000] times by 2 threads without critical section.
      Var g_n is [2000].

      如果加大每個線程的循環次數,結果將大不相同:

      $ ./thdincr_nosync 10000000
      Loops [10000000] times by 2 threads without critical section.
      Var g_n is [18655665].

      造成以上問題的原因在于下面的執行序列:

      1. 線程1將g_n的值賦給局部變量loc。假設g_n的當前值為1000。

      2. 線程1的時間片用盡,線程2開始執行。

      3. 線程2執行多次循環:將g_n的值改為其他的值,例如3000,線程2的時間片用盡。

      4. 線程1重新獲得時間片,并從上次停止處恢復執行。線程1在上次運行時,已將g_n的值(1000)賦給loc,現在遞增loc,再將loc的值1001賦給g_n。此時線程2之前遞增操作的結果遭到覆蓋。

      如果使用上面同樣的命令行參數運行該程序多次,g_n的值會出現很大波動:

      $ ./thdincr_nosync 10000000
      Loops [10000000] times by 2 threads without critical section.
      Var g_n is [14085995].

      $ ./thdincr_nosync 10000000
      Loops [10000000] times by 2 threads without critical section.
      Var g_n is [13590133].

      $ ./thdincr_nosync 10000000
      Loops [10000000] times by 2 threads without critical section.
      Var g_n is [20000000].

      $ ./thdincr_nosync 10000000
      Loops [10000000] times by 2 threads without critical section.
      Var g_n is [16550684].

      這一行為結果的不確定性,原因在于內核CPU調度順序的不可預測性。若在復雜的程序中發生這種不確定結果的行為,意味著此類錯誤將偶爾發作,難以復現,因此也很難發現。如果使用如下語句:

      g_n++;        /* 或者: ++g_n */

      來替換thread_routine內for循環中的3條語句,似乎可以解決這一問題,不過在很多硬件架構上,編譯器在將這條語句轉換成機器碼時,其效果仍等同于原先thread_routine內for循環中的3條語句。即換成一條語句并非意味著該操作就是原子操作。

      為了避免上述同一行為的結果不確定性,必須使用某種技術來確保同一時刻只有一個線程可以訪問共享資源,在Linux/Unix系統中,互斥量mutex(mutual exclusion的縮寫)就是為這種情況設計的一種線程間同步技術,可以使用互斥量來保證對任意共享資源的原子訪問。

      互斥量有兩種狀態:已鎖定和未鎖定。任何時候,至多只有一個線程可以鎖定該互斥量。試圖對已經鎖定的互斥量再次加鎖,將可能阻塞線程或者報錯,具體取決于加鎖時使用的方法。

      靜態分配的互斥量:

      互斥量既可以像靜態變量那樣分配,也可以在運行時動態創建,例如,通過malloc在堆中分配,或者在棧上的自動變量,下面的語句展示了如何初始化靜態分配的互斥量:

      static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

      互斥量的加鎖和解鎖操作:

      初始化之后,互斥量處于未鎖定狀態。函數pthread_mutex_lock()可以鎖定某一互斥量,而函數pthread_mutex_unlock()可以將一個已經鎖定的互斥量解鎖。

      #include <pthread.h>
      
      int pthread_mutex_lock(pthread_mutex_t *mutex);
      int pthread_mutex_unlock(pthread_mutex_t *mutex);
      
      /* 兩個函數在成功時返回值為0,失敗時返回一個正值代表錯誤號。 */

       

      代碼示例2:使用靜態分配的互斥量保護對全局變量的訪問

       1 #include <pthread.h>
       2 #include <stdio.h>
       3 #include <stdlib.h>
       4 
       5 static int g_n = 0;
       6 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
       7 
       8 static void *
       9 thread_routine(void *arg)
      10 {
      11     int n_loops = *((int *)arg);
      12     int loc;
      13     int j;
      14     int s;
      15     
      16     for (j = 0; j < n_loops; j++)
      17     {
      18         s = pthread_mutex_lock(&mtx);
      19         if (s != 0)
      20         {
      21             perror("error pthread_mutex_lock.\n");
      22             exit(EXIT_FAILURE);
      23         }
      24         
      25         loc = g_n;
      26         loc++;
      27         g_n = loc;
      28         
      29         s = pthread_mutex_unlock(&mtx);
      30         if (s != 0)
      31         {
      32             perror("error pthread_mutex_unlock.\n");
      33             exit(EXIT_FAILURE);
      34         }
      35     }
      36     
      37     return 0;
      38 }
      39 
      40 int
      41 main(int argc, char *argv[])
      42 {
      43     pthread_t t1, t2;
      44     int n_loops, s;
      45     
      46     n_loops = (argc > 1) ? atoi(argv[1]) : 10000000;
      47     
      48     s = pthread_create(&t1, 0, thread_routine, &n_loops);
      49     if (s != 0)
      50     {
      51         perror("error pthread_create.\n");
      52         exit(EXIT_FAILURE);
      53     }
      54     
      55     s = pthread_create(&t2, 0, thread_routine, &n_loops);
      56     if (s != 0)
      57     {
      58         perror("error pthread_create.\n");
      59         exit(EXIT_FAILURE);
      60     }
      61     
      62     s = pthread_join(t1, 0);
      63     if (s != 0)
      64     {
      65         perror("error pthread_join.\n");
      66         exit(EXIT_FAILURE);
      67     }
      68     
      69     s = pthread_join(t2, 0);
      70     if (s != 0)
      71     {
      72         perror("error pthread_join.\n");
      73         exit(EXIT_FAILURE);
      74     }
      75 
      76     printf("Var g_n is [%d].\n", g_n);
      77     exit(EXIT_SUCCESS);
      78 }

      運行此示例代碼生成的程序,從結果中可以看出對g_n的遞增操作總能保持正確:

      $ ./thdincr_mutex 10000000
      Var g_n is [20000000].
      $ ./thdincr_mutex 10000000
      Var g_n is [20000000].
      $ ./thdincr_mutex 10000000
      Var g_n is [20000000].
      $ ./thdincr_mutex 10000000
      Var g_n is [20000000].
      $ ./thdincr_mutex 10000000
      Var g_n is [20000000].

      代碼示例3:使用動態分配的互斥量保護對全局變量的訪問

        1 #include <pthread.h>
        2 #include <stdio.h>
        3 #include <stdlib.h>
        4 #include <errno.h>
        5 
        6 static int g_n = 0;
        7 
        8 static void *
        9 thread_routine(void *arg)
       10 {
       11     void **args = (void **)arg;
       12     int n_loops = (int)(args[0]);
       13     int loc;
       14     int j;
       15     int s;
       16     pthread_mutex_t *mtx = (pthread_mutex_t *)(args[1]);
       17     
       18     for (j = 0; j < n_loops; j++)
       19     {
       20         s = pthread_mutex_lock(mtx);
       21         if (s != 0)
       22         {
       23             printf("error pthread_mutex_lock. return:[%d] errno:[%d]\n", s, errno);
       24             exit(EXIT_FAILURE);
       25         }
       26         
       27         loc = g_n;
       28         loc++;
       29         g_n = loc;
       30         
       31         s = pthread_mutex_unlock(mtx);
       32         if (s != 0)
       33         {
       34             perror("error pthread_mutex_unlock.\n");
       35             exit(EXIT_FAILURE);
       36         }
       37     }
       38     
       39     return 0;
       40 }
       41 
       42 int
       43 main(int argc, char *argv[])
       44 {
       45     int n_loops, s;
       46     pthread_t t1, t2;
       47     pthread_mutex_t mtx;
       48     pthread_mutexattr_t mtx_attr;
       49     void *args[2];
       50     
       51     s = pthread_mutexattr_init(&mtx_attr);
       52     if (s != 0)
       53     {
       54         perror("error pthread_mutexattr_init.\n");
       55         exit(EXIT_FAILURE);
       56     }
       57     
       58     s = pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_ERRORCHECK);
       59     if (s != 0)
       60     {
       61         perror("error pthread_mutexattr_settype.\n");
       62         exit(EXIT_FAILURE);
       63     }
       64     
       65     s = pthread_mutex_init(&mtx, &mtx_attr);
       66     if (s != 0)
       67     {
       68         perror("error pthread_mutex_init.\n");
       69         exit(EXIT_FAILURE);
       70     }
       71     
       72     s = pthread_mutexattr_destroy(&mtx_attr);
       73     if (s != 0)
       74     {
       75         perror("error pthread_mutexattr_destroy.\n");
       76         exit(EXIT_FAILURE);
       77     }
       78     
       79     n_loops = (argc > 1) ? atoi(argv[1]) : 10000000;
       80     
       81     args[0] = (void *)n_loops;
       82     args[1] = (void *)&mtx;
       83     s = pthread_create(&t1, 0, thread_routine, &args);
       84     if (s != 0)
       85     {
       86         perror("error pthread_create.\n");
       87         exit(EXIT_FAILURE);
       88     }
       89     
       90     s = pthread_create(&t2, 0, thread_routine, &args);
       91     if (s != 0)
       92     {
       93         perror("error pthread_create.\n");
       94         exit(EXIT_FAILURE);
       95     }
       96     
       97     s = pthread_join(t1, 0);
       98     if (s != 0)
       99     {
      100         perror("error pthread_join.\n");
      101         exit(EXIT_FAILURE);
      102     }
      103     
      104     s = pthread_join(t2, 0);
      105     if (s != 0)
      106     {
      107         perror("error pthread_join.\n");
      108         exit(EXIT_FAILURE);
      109     }
      110     
      111     s = pthread_mutex_destroy(&mtx);
      112     if (s != 0)
      113     {
      114         perror("error pthread_mutex_destroy.\n");
      115         exit(EXIT_FAILURE);
      116     }
      117     
      118     printf("Var g_n is [%d].\n", g_n);
      119     exit(EXIT_SUCCESS);
      120 }

      多次運行示例3代碼生成的程序會看到與示例2代碼的程序同樣的結果。

      本文展示了Linux/Unix線程間同步技術---互斥量的基本功能和基礎使用方法,在后面的文章中將會討論互斥量的其他內容,如鎖定互斥量的另外2個API: pthread_mutex_trylock()和pthread_mutex_timedlock() ,互斥量的性能,互斥量的死鎖等。歡迎大家參與討論。

      本文參考了Michael Kerrisk的著作《The Linux Programming Interface》(中文版名為:Linux/Unix系統編程手冊)第30章的內容,版權相關的問題請聯系作者或者相應的出版社。

       

      posted on 2014-03-23 11:55  拾貝雜苑  閱讀(564)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: 中文字幕乱码视频32| 国产无遮挡真人免费视频| 日本高清无卡码一区二区| 欧洲熟妇色xxxx欧美老妇免费| 久久综合婷婷成人网站| 日本一区二区三深夜不卡| 狠狠色狠狠综合久久| 国产成人无码免费视频在线| 久久中文字幕无码专区| 人妻日韩精品中文字幕| 99热门精品一区二区三区无码| 国产精品av中文字幕| 日本精品成人一区二区三区视频| 免费午夜无码片在线观看影院| 男女啪啪18禁无遮挡激烈| 常州市| 99久久精品国产一区色| 手机看片日本在线观看视频| 乐清市| 疯狂做受xxxx高潮欧美日本| 国产日韩在线亚洲色视频| 国产激情艳情在线看视频| 成人永久性免费在线视频| 中文字幕第55页一区| 在线观看中文字幕国产码| 91国内精品久久精品一本| 亚洲人妻一区二区精品| 在线亚洲午夜片av大片| 日日碰狠狠添天天爽五月婷| 99久久精品美女高潮喷水| 亚洲欧洲久久激情久av| 男女激情一区二区三区| 性欧美老妇另类xxxx| 久播影院无码中文字幕| 99久久无码私人网站| 在熟睡夫面前侵犯我在线播放| 起碰免费公开97在线视频| 综1合AV在线播放| 久久中文字幕日韩无码视频| 99久久亚洲综合精品成人| 国产乱码精品一区二区三|