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

 

posted @ 2019-01-13 20:07  游戏进行中  阅读(1029)  评论(0编辑  收藏  举报