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

原文地址:https://www.cnblogs.com/kele-dad/p/10263781.html

时间: 2024-10-07 14:07:55

四十二、Linux 线程——线程同步之条件变量之线程状态转换的相关文章

使用互斥量和条件变量实现线程同步控制

管程(monitor)说明 在并发编程中,管程(monitor)是一个同步构件,管程实现了同一时间点,最多只有一个线程可以执行管程的某个子程序.与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程的实现很大程度上简化了程序设计. 管程可以确保一次只有一个进程执行管程中的程序,因此程序员不需要显式地编写同步代码,但是如果需要就某些特定条件上的同步,则需要定义一些条件结构(condition variable)来实现,并且对条件变量的操作仅有wait()和signal(),如下: condit

“全栈2019”Java多线程第四十二章:获取线程与读写锁的保持数

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第四十二章:获取线程与读写锁的保持数 下一章 "全栈2019"Java多线程第四十三章:查询是否有线程在等待读写锁 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复&quo

Linux C编程之二十二 Linux线程池实现

一.线程池实现原理 1. 管理者线程 (1)计算线程不够用 创建线程 (2) 空闲线程太多 a. 销毁 更新要销毁的线程个数 通过条件变量完成的 b. 如果空闲太多,任务不够 线程阻塞在该条件变量上 c. 发送信号 pthread_cond_signal 2. 线程池中的线程 (1)从任务队列中取数据 任务队列任务 执行任务 (2)销毁空闲的线程 让线程执行pthread_exit 阻塞空闲的线程收到信号: 解除阻塞          只有一个往下执行          在执行任务之前做了销毁操

四十一、Linux 线程——线程同步之条件变量

41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待的线程,线程在条件变量上等待和通知,互斥锁用来保护等待队列(对等待队列上锁),条件变量通常和互斥锁一起使用 条件变量允许线程等待特定条件发生,当条件不满足时,线程通常先进入阻塞状态,等待条件发生变化.一旦其它的某个线程改变了条件,可唤醒一个或多个阻塞的线程 具体的判断条件还需用户给出 条件变量数据类

linux线程同步(2)-条件变量

一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区.条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行.通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行. 条件变量总是和互斥量一起使用,互斥量保护着条件变量,防止多个

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执

linux线程间通信之条件变量和互斥量

一.条件变量定义 有的时候仅仅依靠锁住共享资源来使用它是不够的.有时候共享资源只有某些状态的时候才能够使用.比方说,某个线程如果要从堆栈中读取数据,那么如果栈中没有数据就必须等待数据被压栈.这种情况下的同步使用互斥锁是不够的.另一种同步的方式--条件变量,就可以使用在这种情况下.条件变量(Condition Variable)是线程间的一种同步机制,提供给两个线程协同完成任务的一种方法,使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止.条件变量的测试一般是用互斥量来保护的,用来确保每

程序员的奋斗史(四十二)——大学断代史(六)——我与图书馆

文/温国兵 作为一个爱读书之人,图书馆简直是人间天堂.反之,不过地狱. 读书的好处在于,可以穿越古今中外,超越时间和空间的界限,到达你想到达的地方.你可以回到唐朝和诗仙酌酒言欢,可以回到战国和庄子高谈庄周梦蝶.鲲鹏之硕,可以回到18世纪的法国聆听哲人卢梭的教导,可以回到19世纪的德国瞻仰尼采的智慧,可以回到20世纪的中国感受王小波的特立独行,可以回到春秋时期领略老子的道,可以回到20世纪感受徐志摩的唯美诗歌--书中自有黄金屋,书中自有颜如玉,从书中可以获取到广阔的精神食粮,指引着我们前进,教导我

NeHe OpenGL教程 第四十二课:多重视口

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十二课:多重视口 多重视口 画中画效果,很酷吧.使用视口它变得很简单,但渲染四次可会大大降低你的显示速度哦:) 欢迎来到充满趣味的另一课.这次我将向你展示怎样在单个窗口内显示多个视口.这些视口在窗口模式下能正确的调整大小.其中有