多线程的生产者和消费者问题
2015-06-12 14:51
120 查看
多线程的生产者和消费者问题是比较经典的多线程问题,如果知道编码解决生产者和消费者问题,那么对于多线程应该基本算掌握了。我不知道大家的生产者和消费者问题是怎么样的(应该有几个版本吧),这里我说下我的生产者和消费者问题:
有多个生产线程,他们只负责生产资源;有多个消费者,同样他们只负责消费。但是他们需要满足下面条件:
生产者:只有当资源没有的时候,生产者才开始生产,但是为了防止浪费,每次只能生产指定数量的资源。当生产者生产完足够资源时,就进入睡眠,同时叫醒消费者去消费;
消费者:只有有资源时消费者才会去消费,当然每次消费多少可以自己设置。如果发现资源消费完了,则要马上叫生产者去生产,而消费者马上进入睡眠;
涉及到的知识:线程基础知识、多线程同步、互斥量、条件变量;可以参考: linux环境编程之多线程同步
生产者程序:
生产者分析:
首先进入死循环,不停的抢锁,抢到锁后查看下是否符合条件:
不符合则解锁,等0.5秒,让其他线程去抢占(主要是让消费者抢到锁去消费)。其实这里有个问题,如果有多个生产者,而且刚好每次都是生产者得到锁,那么就是个死锁了。虽然这种可能性比较小,但是这也有可能。就算不产生死锁,也会影响性能,让不相关的线程去抢占锁(上锁 == 判断 == 解锁 会消耗时间);
符合条件,则抢到锁的生产线程负责生产资源,生产完后留下姓名,最后叫醒消费线程去消费,自己则睡眠休息;这同样有个问题:就是生产线程会去捣乱,会去抢锁,然后判断,解锁。这会降低系统性能,后期可以想办法改进下。
当资源条件改变后,则生产线程(上次生产的那个线程)会被叫醒,这时候锁都在他手上。然后解锁,让大家去抢锁,这里延迟了0.5秒,是不让这个线程再去抢锁了(0.5秒虽然很长,但也有可能还是上次生产的那个线程获取到了锁),同样这也有上面的问题;
消费者程序:
和生产者类似,这里就不详细分析了。首先抢占锁,判断是否有资源,没有的话则等生产着去生产。如果有,则进入消费,消费完后再判断下是否把资源全部消耗掉了,如果没有,则让其他线程进入消费;如果有,则通知生产线程去生产,而自己休眠等待通知;
缺陷:
这个解决方案有两个缺陷:
1、多生产者时,当生产完后,该生产资源的线程睡眠(同时唤醒所有消费),但其他生产线程会和消费线程抢锁。多消费者,同样的情况;
2、开始的时候其实是没有唤醒,比如消费线程开始的时候没有资源,不是通知生产者生产(这时候生产线程也没有休眠,就算通知也没有用),而是循环等待,希望生产线程能获取到锁去生产。
解决:
解决方法可以试试先判断资源条件是否符合,符合进入上锁然后操作,不符合则等待睡眠。但因为条件检查和上锁不是原子操作,容易变成死锁。还有其他一些问题。后期再研究下,或者大家帮忙解决下(不过自己研究会更有乐趣,可以提供思路)
主函数程序:
转载地址:/article/1530592.html
有多个生产线程,他们只负责生产资源;有多个消费者,同样他们只负责消费。但是他们需要满足下面条件:
生产者:只有当资源没有的时候,生产者才开始生产,但是为了防止浪费,每次只能生产指定数量的资源。当生产者生产完足够资源时,就进入睡眠,同时叫醒消费者去消费;
消费者:只有有资源时消费者才会去消费,当然每次消费多少可以自己设置。如果发现资源消费完了,则要马上叫生产者去生产,而消费者马上进入睡眠;
涉及到的知识:线程基础知识、多线程同步、互斥量、条件变量;可以参考: linux环境编程之多线程同步
生产者程序:
#include<pthread.h> #include<stdio.h> #include<stdlib.h> #include<fcntl.h> static int source = 0; // 定义资源为个整型数,当然也可以定义为一个结构体 static pthread_mutex_t lock; // 定义个互斥量用来锁住资源 static pthread_cond_t con; // 定义条件变量 static pthread_t pro_t1, pro_t2, con_t1, con_t2, con_t3, con_t4; void* product(void *arg) { while(1){ if (!pthread_mutex_lock(&lock)){ if (0 == source){ source += 3; // 每次都生产3个资源 sleep(1); // 为了查看打印的数据而已 // 查看下是哪个生产者来生产的 if (pro_t1 == pthread_self()) printf("\n\npro1 make source %d ==> %d\n", source-3, source); else if (pro_t2 == pthread_self()) printf("\n\npro2 make source %d ==> %d\n", source-3, source); else printf("error pro\n"); // 已经改变了条件,把条件变量上的等待线程都唤醒,让他们自行抢占 pthread_cond_broadcast(&con); pthread_cond_wait(&con, &lock);// 生产者生产完休息 } pthread_mutex_unlock(&lock); } usleep(500);// 为了防止总是同一个生产者去生产,也给消费者时间去消费 } return (void*)0; }
生产者分析:
首先进入死循环,不停的抢锁,抢到锁后查看下是否符合条件:
不符合则解锁,等0.5秒,让其他线程去抢占(主要是让消费者抢到锁去消费)。其实这里有个问题,如果有多个生产者,而且刚好每次都是生产者得到锁,那么就是个死锁了。虽然这种可能性比较小,但是这也有可能。就算不产生死锁,也会影响性能,让不相关的线程去抢占锁(上锁 == 判断 == 解锁 会消耗时间);
符合条件,则抢到锁的生产线程负责生产资源,生产完后留下姓名,最后叫醒消费线程去消费,自己则睡眠休息;这同样有个问题:就是生产线程会去捣乱,会去抢锁,然后判断,解锁。这会降低系统性能,后期可以想办法改进下。
当资源条件改变后,则生产线程(上次生产的那个线程)会被叫醒,这时候锁都在他手上。然后解锁,让大家去抢锁,这里延迟了0.5秒,是不让这个线程再去抢锁了(0.5秒虽然很长,但也有可能还是上次生产的那个线程获取到了锁),同样这也有上面的问题;
消费者程序:
void* consume(void *arg) { while(1){ if (!pthread_mutex_lock(&lock)){// 抢锁 if (source){ source--;// 消费资源 sleep(1); // 打印谁消费了资源 if (con_t1 == pthread_self()) printf("con1 make source %d ==> %d\n", source+1, source); else if (con_t2 == pthread_self()) printf("con2 make source %d ==> %d\n", source+1, source); else if (con_t3 == pthread_self()) printf("con3 make source %d ==> %d\n", source+1, source); else if (con_t4 == pthread_self()) printf("con4 make source %d ==> %d\n", source+1, source); else printf("error con\n"); if(!source){// 查看下资源是否还有 pthread_cond_broadcast(&con);// 如果没有资源了,则通知生产者开始工作了 pthread_cond_wait(&con, &lock);// 消费者进入睡眠等待生产者生产好资源来 } } pthread_mutex_unlock(&lock); } usleep(500);// 给生产者时间去生产,或者给其他消费者机会去获取锁去消费 } return (void*)0; }消费者分析:
和生产者类似,这里就不详细分析了。首先抢占锁,判断是否有资源,没有的话则等生产着去生产。如果有,则进入消费,消费完后再判断下是否把资源全部消耗掉了,如果没有,则让其他线程进入消费;如果有,则通知生产线程去生产,而自己休眠等待通知;
缺陷:
这个解决方案有两个缺陷:
1、多生产者时,当生产完后,该生产资源的线程睡眠(同时唤醒所有消费),但其他生产线程会和消费线程抢锁。多消费者,同样的情况;
2、开始的时候其实是没有唤醒,比如消费线程开始的时候没有资源,不是通知生产者生产(这时候生产线程也没有休眠,就算通知也没有用),而是循环等待,希望生产线程能获取到锁去生产。
解决:
解决方法可以试试先判断资源条件是否符合,符合进入上锁然后操作,不符合则等待睡眠。但因为条件检查和上锁不是原子操作,容易变成死锁。还有其他一些问题。后期再研究下,或者大家帮忙解决下(不过自己研究会更有乐趣,可以提供思路)
主函数程序:
int main(int argc, char* argv[]) { pthread_attr_t attr; // 互斥量锁属性 pthread_attr_init(&attr);// 初始化互斥量锁属性 pthread_mutex_init(&lock, NULL);// 初始化互斥量锁 pthread_cond_init(&con, NULL); // 初始化条件变量 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);// 设置锁属性 pthread_create(&con_t1, &attr, &consume, NULL);// 创建消费线程和生产线程 pthread_create(&con_t2, &attr, &consume, NULL); pthread_create(&con_t3, &attr, &consume, NULL); pthread_create(&con_t4, &attr, &consume, NULL); pthread_create(&pro_t1, &attr, &product, NULL); pthread_create(&pro_t2, &attr, &product, NULL); pause();// 挂起主线程,主线程不能死 pthread_cond_destroy(&con);// 下面都是注销函数,做扫尾工作 pthread_mutex_destroy(&lock); pthread_attr_destroy(&attr); return 0; }
转载地址:/article/1530592.html
相关文章推荐
- [swustoj 917] K-lucky-number
- linux 下网络流量监控
- 在VirtualBox下安装Ubuntu虚拟机出现The system is running in low-graphics mode解决
- hdu 2176 取石子游戏
- AndroidStudio 文档自动提示&代码提示补全
- 模板方法模式
- Android应用性能优化之使用SparseArray替代HashMap
- openwrt下安装nohup
- unity 如何改变游戏中鼠标样式
- mysql计算指定时间内TPS
- 安卓--子线程和主线程之间的交互实例(时钟)
- jQuery插件开发的模式和结构
- windows和linux中的socket
- 矩阵范数(martix norm) --维基百科
- ZTE
- Maven项目中mvn clean后找不到测试类问题
- WIN8 IE浏览器打不开
- HDU 4370 0 or 1(巧妙思路转化,0/1规划,最短路SPFA)
- UVALive - 4621 Cav 贪心 + 分析
- java 获取时间相关总结