四十二、Linux 線程——線程同步之條件變量之線程狀態轉換
阿新 • • 發佈:2019-01-13
include com img %d src usleep span info clu
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 }
四十二、Linux 線程——線程同步之條件變量之線程狀態轉換