1. 程式人生 > >四十二、Linux 執行緒——執行緒同步之條件變數之執行緒狀態轉換

四十二、Linux 執行緒——執行緒同步之條件變數之執行緒狀態轉換

42.1 執行緒狀態轉換

42.1.1 狀態轉換圖

  

42.1.2 一個執行緒計算,多個執行緒獲取的案例

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <pthread.h>
  4 #include <unistd.h>
  5 
  6 /** 兩個執行緒定義的共享資源 */
  7 typedef struct {
  8     int res;
  9     int counter;            ///< 用於統計獲取結果執行緒的數量
 10
pthread_cond_t cond; ///< 條件變數 11 pthread_mutex_t mutex; ///< 互斥鎖 12 }Result; 13 14 15 /** 計算並將結果放置在 Result 中的執行緒執行函式 */ 16 void *set_fn(void *arg) 17 { 18 Result *r = (Result *)arg; 19 int i = 0; 20 int sum = 0; 21 22 for(; i <= 100; i++){ 23 sum += i;
24 } 25 26 /** 將結果放置到 Result 中 */ 27 r->res = sum; 28 29 pthread_mutex_lock(&r->mutex); 30 /** 判斷獲取結果的執行緒是否達到指定的數量 */ 31 while(r->counter < 2){ 32 pthread_mutex_unlock(&r->mutex); 33 usleep(100); 34 pthread_mutex_lock(&r->mutex);
35 } 36 pthread_mutex_unlock(&r->mutex); 37 38 /** 通知喚醒等待的那個獲取結果的執行緒 */ 39 pthread_cond_broadcast(&r->cond); 40 41 return (void *)0; 42 } 43 44 /** 獲得結果的執行緒執行函式 */ 45 void *get_fn(void *arg) 46 { 47 Result *r = (Result *)arg; 48 49 /** 對兩個執行緒共享的判斷條件進行保護(加鎖) */ 50 /** 兩個執行緒對判斷條件的操作是互斥的 */ 51 pthread_mutex_lock(&r->mutex); 52 /** 有一個執行緒準備好了,則計數器 +1 */ 53 r->counter++; 54 55 /** 獲取結果的執行緒等待 */ 56 pthread_cond_wait(&r->cond, &r->mutex); 57 58 /** 被喚醒後 */ 59 pthread_mutex_unlock(&r->mutex); 60 61 /** 去獲取計算結果 */ 62 int res = r->res; 63 printf("0x%lx get sum is %d\n", pthread_self(), res); 64 65 return (void *)0; 66 } 67 68 int main(void) 69 { 70 int err; 71 pthread_t cal, get1, get2; 72 73 Result r; 74 r.counter = 0; 75 pthread_cond_init(&r.cond, NULL); 76 pthread_mutex_init(&r.mutex, NULL); 77 78 /** 啟動獲取結果的執行緒 */ 79 if((err = pthread_create(&get1, NULL, get_fn, (void *)&r)) != 0){ 80 perror("pthread create error"); 81 } 82 83 if((err = pthread_create(&get2, NULL, get_fn, (void *)&r)) != 0){ 84 perror("pthread create error"); 85 } 86 87 /** 啟動計算結果的執行緒 */ 88 if((err = pthread_create(&cal, NULL, set_fn, (void *)&r)) != 0){ 89 perror("pthread create error"); 90 } 91 92 pthread_join(cal, NULL); 93 pthread_join(get1, NULL); 94 pthread_join(get2, NULL); 95 96 pthread_cond_destroy(&r.cond); 97 pthread_mutex_destroy(&r.mutex); 98 99 pthread_cond_destroy(&r.cond); 100 pthread_mutex_destroy(&r.mutex); 101 return 0; 102 }

  編譯執行結果如下:

  

42.2 讀者-寫者案例

   

  • 幾種情況:
    • 1 個寫者,1 個讀者
    • 1 個寫者,多個讀者
    • 多個寫者,多個讀者

  完成第一種情況:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <pthread.h>
  4 #include <string.h>
  5 #include <unistd.h>
  6 
  7 typedef struct {
  8     int             value;
  9 
 10     /** 讀者 */
 11     pthread_cond_t  rc;
 12     pthread_mutex_t rm;
 13     int             r_wait;
 14 
 15     /** 寫者 */
 16     pthread_cond_t  wc;
 17     pthread_mutex_t wm;
 18     int             w_wait;
 19 }Storage;
 20 
 21 /** 寫入資料的函式 */
 22 void set_data(Storage *s, int value)
 23 {
 24     s->value = value;
 25 }
 26 
 27 /** 獲取資料的函式 */
 28 int get_data(Storage *s)
 29 {
 30     return s->value;
 31 }
 32 
 33 /** 寫者執行緒執行函式定義 */
 34 void *set_th(void *arg)
 35 {
 36     Storage *s = (Storage *)arg;
 37     int i = 1;
 38     for(; i <= 100; i++){
 39         /** 寫入資料 */
 40         set_data(s, i +100);
 41         printf("0x%lx(%-5d) write data : %d\n", pthread_self(), i, i + 100);
 42 
 43         pthread_mutex_lock(&s->rm);
 44         /** 判斷讀者執行緒是否準備好 */
 45         while(!s->r_wait){
 46             pthread_mutex_unlock(&s->rm);
 47             sleep(1);
 48             pthread_mutex_lock(&s->rm);
 49         }
 50         s->r_wait = 0;
 51         pthread_mutex_unlock(&s->rm);
 52 
 53         /** 通知讀者執行緒讀取資料 */
 54         pthread_cond_broadcast(&s->rc);
 55 
 56         /** 寫者執行緒自阻塞等待讀者執行緒通知已經讀取完畢,
 57          * 然後喚醒寫者執行緒繼續寫入資料 */
 58         pthread_mutex_lock(&s->wm);
 59         s->w_wait = 1;
 60         pthread_cond_wait(&s->wc, &s->wm);
 61         pthread_mutex_unlock(&s->wm);
 62 
 63     }
 64     return (void *)0;
 65 }
 66 
 67 /** 讀者執行緒執行函式定義 */
 68 void *get_th(void *arg)
 69 {
 70     Storage *s = (Storage *)arg;
 71     int i = 1;
 72     for(; i <= 100; i++){
 73         pthread_mutex_lock(&s->rm);
 74         s->r_wait = 1;
 75         pthread_cond_wait(&s->rc, &s->rm);
 76         pthread_mutex_unlock(&s->rm);
 77 
 78         /** 讀者執行緒被喚醒後讀取資料 */
 79         int value = get_data(s);
 80         printf("0x%lx(%-5d) read data: %d\n", pthread_self(), i, value);
 81 
 82         pthread_mutex_lock(&s->wm);
 83         /** 判斷寫者執行緒是否準備好 */
 84         while(!s->w_wait){
 85             pthread_mutex_unlock(&s->wm);
 86             sleep(1);
 87             pthread_mutex_lock(&s->wm);
 88         }
 89         /** 喚醒寫者執行緒 */
 90         s->w_wait = 0;
 91         pthread_mutex_unlock(&s->wm);
 92         pthread_cond_broadcast(&s->wc);
 93 
 94     }
 95     return (void *)0;
 96 }
 97 
 98 int main(void)
 99 {
100     int err;
101     pthread_t   rth, wth;
102 
103     Storage s;
104     s.r_wait = 0;
105     s.w_wait = 0;
106     pthread_mutex_init(&s.rm, NULL);
107     pthread_mutex_init(&s.wm, NULL);
108     pthread_cond_init(&s.rc, NULL);
109     pthread_cond_init(&s.wc, NULL);
110 
111     /** 建立一個讀者執行緒和寫者執行緒 */
112     if((err = pthread_create(&rth, NULL, get_th, (void *)&s)) != 0){
113         perror("pthread create error");
114     }
115 
116     if((err = pthread_create(&wth, NULL, set_th, (void *)&s)) != 0){
117         perror("pthread create error");
118     }
119 
120     pthread_join(rth, NULL);
121     pthread_join(wth, NULL);
122 
123     pthread_mutex_destroy(&s.rm);
124     pthread_mutex_destroy(&s.wm);
125     pthread_cond_destroy(&s.rc);
126     pthread_cond_destroy(&s.wc);
127 
128     return 0;
129 }