Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题
来源:互联网 发布:美团摄影师知乎 编辑:程序博客网 时间:2024/04/28 03:37
前面的一片文章我们已经讲过使用信号量解决生产者消费者问题,那么什么情况下我们需要引入条件变量呢?
这里借用 http://www.cnblogs.com/ngnetboy/p/3521547.html 的解释:
假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与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;}
- Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题
- Linux多线程实践(8) --Posix条件变量解决生产者消费者问题
- Linux多线程实践(8) --Posix条件变量解决生产者消费者问题
- Linux多线程实践(五 )Posix信号量和互斥锁解决生产者消费者问题
- Linux多线程实践(5) --Posix信号量与互斥量(解决生产者消费者问题)
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
- POSIX条件变量(生产者,消费者)
- 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题
- Java多线程之生产者消费者问题<二>:使用重入锁、条件变量优雅地解决生产者消费者问题
- linux网络编程之posix 线程(四):posix 条件变量与互斥锁 示例生产者--消费者问题
- linux网络编程之posix 线程(四):posix 条件变量与互斥锁 示例生产者--消费者问题
- Linux多线程,生产者消费者算法和条件变量的使用
- 使用POSIX线程解决“生产者/消费者”问题
- posix 条件变量与互斥锁 示例生产者--消费者问题 .
- 互斥锁加条件变量解决生产者消费者问题
- Linux多线程实践(7) --Posix条件变量
- Linux多线程消费者和生产者模型实例(互斥锁和条件变量使用)
- 仅支持英文和阿拉伯数字 加密解密Demo
- 加油吧半瓶子醋~~~
- ogre dx模式,创建设备失败 -2005530516
- Android Studio安装插件
- 如何使对话框程序启动以及主窗口最小化时不在任务栏上显示
- Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题
- UGUI(一)序列图,表情动画
- 关于css float
- JSONKit在项目中使用设置(使用时报错解决方案)
- 蓝桥杯-入门训练-求圆的面积
- 大二的第一学期总结
- ExtJS Panel 学习示例
- Python入门教程
- .FPGA学习的一些误区