四十二、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 }