前面的一片文章我们已经讲过使用信号量解决生产者消费者问题。那么什么情况下我们须要引入条件变量呢?

这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.html 的解释:

如果有共享的资源sum,与之相关联的mutex 是lock_s.如果每一个线程对sum的操作非常easy的,与sum的状态无关,比方仅仅是sum++.那么仅仅用mutex足够了.程序猿仅仅要确保每一个线程操作前,取得lock,然后sum++,再unlock就可以.每一个线程的代码将像这样:

add()
{pthread_mutex_lock(lock_s);sum++;pthread_mutex_unlock(lock_s);
}

假设操作比較复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零. 这样的情况下,假设仅仅用mutex, 则t3须要一个循环,每一个循环里先取得lock_s,然后检查sum的状态,假设sum>=100,则打印并清零,然后unlock.假设sum<100,则unlock,并sleep()本线程合适的一段时间。

这个时候,t0,t1,t2的代码不变,t3的代码例如以下:

print()
{while (1){pthread_mutex_lock(lock_s);if(sum<100){printf(“sum reach 100!”);pthread_mutex_unlock(lock_s);}else{pthread_mutex_unlock(lock_s);my_thread_sleep(100);return OK;}}
}

这样的办法有两个问题

1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,仅仅是lock和unlock,然后sleep().这浪费了CPU处理时间.

2) 为了节省CPU处理时间,t3会在探測到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t4才会醒过来.

3) 这样,程序猿在设置sleep()时间的时候陷入两难境界,设置得太短了节省不了资源,太长了又减少响应速度.真是难办啊!

这个时候,condition variable,从天而降,解救了焦头烂额的你.

你首先定义一个condition variable.

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

t0,t1,t2的代码仅仅要后面加两行,像这样:

add()
{pthread_mutex_lock(lock_s);sum++;pthread_mutex_unlock(lock_s);if(sum>=100)pthread_cond_signal(&cond_sum_ready);
}
而t3的代码则是
print
{pthread_mutex_lock(lock_s);while(sum<100)pthread_cond_wait(&cond_sum_ready, &lock_s);printf(“sum is over 100!”);sum=0;pthread_mutex_unlock(lock_s);return OK;
}

注意两点:

1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 由于假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再又一次lock该mutex, 然后返回.

2) 为什么是while(sum<100),而不是if(sum<100) ?这是由于在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,如果在这个时间差内,还有另外一个线程t4又把sum降低到100下面了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用 while的用意

线程间的同步技术。主要以相互排斥锁和条件变量为主,条件变量和相互排斥所的配合使用能够非常好的处理对于条件等待的线程间的同步问题

Posix条件变量经常使用API:

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond);  int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,  pthread_mutex_t  *mutex,  const  struct timespec *abstime);  int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); 

通常条件变量须要和相互排斥锁同一时候使用, 利用相互排斥量保护条件变量;条件的检測是在相互排斥锁的保护下进行的。

假设一个条件为假,一个线程自己主动堵塞,

并释放等待状态改变的相互排斥锁。假设还有一个线程改变了条件,它就发送信号给关联的条件变量, 并唤醒一个或多个等待在该条件变量上的线程,这些线程将又一次获得相互排斥锁,又一次评价条件。假设将条件变量放到共享内存中, 而两进程可共享读写这段内存,则条件变量能够被用来实现两进程间的线程同步。

条件变量的使用规范:

(一)、等待条件代码
pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
改动条件
pthread_mutex_unlock(&mutex);(二)、给条件发送通知代码
pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);

注意是while而不是if,原因是在信号的中断后还能正常执行。

解决生产者消费者问题(无界缓冲区):

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 1pthread_mutex_t g_mutex;
pthread_cond_t g_cond;pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];int nready = 0;void *consume(void *arg)
{int num = (int)arg;while (1){pthread_mutex_lock(&g_mutex);while (nready == 0){printf("%d begin wait a condtion ...\n", num);pthread_cond_wait(&g_cond, &g_mutex);}printf("%d end wait a condtion ...\n", num);printf("%d begin consume product ...\n", num);--nready;printf("%d end consume product ...\n", num);pthread_mutex_unlock(&g_mutex);sleep(1);}return NULL;
}void *produce(void *arg)
{int num = (int)arg;while (1){pthread_mutex_lock(&g_mutex);printf("%d begin produce product ...\n", num);++nready;printf("%d end produce product ...\n", num);pthread_cond_signal(&g_cond);printf("%d signal ...\n", num);pthread_mutex_unlock(&g_mutex);sleep(1);}return NULL;
}int main(void)
{int i;pthread_mutex_init(&g_mutex, NULL);pthread_cond_init(&g_cond, NULL);for (i = 0; i < CONSUMERS_COUNT; i++)pthread_create(&g_thread[i], NULL, consume, (void *)i);sleep(1);for (i = 0; i < PRODUCERS_COUNT; i++)pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i);for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)pthread_join(g_thread[i], NULL);pthread_mutex_destroy(&g_mutex);pthread_cond_destroy(&g_cond);return 0;
}

转载于:https://www.cnblogs.com/jzssuanfa/p/7081259.html

Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题相关推荐

  1. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  2. 操作系统上机作业--使用条件变量解决生产者、计算者、消费者问题(多线程)

    pc1.c: 使用条件变量解决生产者.计算者.消费者问题 /* • 系统中有3个线程:生产者.计算者.消费者 • 系统中有2个容量为4的缓冲区:buffer1.buffer2 • 生产者生产'a'.' ...

  3. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  4. 【操作系统/OS笔记13】信号量、PV操作、管程、条件变量、生产者消费者问题

    本次笔记内容: 10.1 背景 10.2 信号量 10.3 信号量的使用 10.4 信号量的实现 10.5 管程 文章目录 信号量的提出背景 信号量(semaphore) 信号量数据类型 信号量类似铁 ...

  5. 条件变量(生产者消费者问题)

    问题描述 生产者消费者问题:(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题 ...

  6. 用条件变量实现生产者-消费者模型

    首先介绍一下条件变量 下面用条件变量来实现生产者-消费者模型 大体思路如下:生产者为链表"生产"结点,消费者"消费"结点,如果链表中没有结点,则阻塞消费者线程 ...

  7. 多线程 wait-notify 写一段代码来解决生产者-消费者问题

                                                             生产者-消费者 该模式在现实生活中很常见,在项目开发中也广泛应用,它是线程间通信的经典 ...

  8. Linux多线程之线程同步(条件变量)

    https://www.cnblogs.com/secondtonone1/p/5580203.html

  9. POSIX 条件变量

    1.条件变量 (1)当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了.例如:一个线程访问队列时,发现队列为空,它只能等待,直到其它线程将节点添加到队列中.这种情况就需要 ...

最新文章

  1. 配置单节点伪分布式Hadoop
  2. c# list转为json_ASP.net把datatable与list转成json输出
  3. 一种伪随机交织器的生成方法
  4. 移动端判断手机横竖屏状态
  5. shell 需要注意的点
  6. OpenCV——读取视频文件并写入文件
  7. c语言程序设计实验周信东指针,C语言程序设计实验4数组周信东
  8. VS2010生成的文件在别的机器上运行提示“丢失MSVCR100D.dll”
  9. pytorch之过拟合的处理(Dropout)(笔记五)
  10. 中国摊铺设备市场趋势报告、技术动态创新及市场预测
  11. 从入门到入土:基于Python实现百度查询返回结果真实url读取及域名读取
  12. [NAACL19]基于DIORA的无监督隐式句法树归纳
  13. (十五)洞悉linux下的Netfilteriptables:开发自己的hook函数【实战】
  14. 计算机二级c语言题库选择题,计算机二级C语言真题选择题
  15. 2022年嵌入式系统设计师考试大纲
  16. 行星轨迹制作_用3ds max制作三维行星运动动画
  17. 微信小程序如何从数组里取值_微信小程序 怎么数组里面值
  18. 一个SQL tvp+.net的例子
  19. Altium Designer简明教程2
  20. 虚拟化在防泄密领域的缺点

热门文章

  1. protel99se 问题汇总(不定期更新)
  2. git报ssh variant 'simple' does not support setting port解决办法
  3. C#通过COM组件操作IE浏览器(四):实用代码总结
  4. Bzoj 3343: 教主的魔法(分块+二分答案)
  5. LeetCode——Kth Largest Element in an Array
  6. Mysql 5.7.10以上版本安装大坑
  7. 图文解说:Nginx+tomcat配置集群负载均衡
  8. 关于EXCEL数据导入到SQLServer中字段存在NULL的问题
  9. C#.net技术内幕04-集合
  10. 牛客假日团队赛2 A.买一送一