多线程的生产者和消费者问题是比较经典的多线程问题,如果知道编码解决生产者和消费者问题,那么对于多线程应该基本算掌握了。我不知道大家的生产者和消费者问题是怎么样的(应该有几个版本吧),这里我说下我的生产者和消费者问题:
有多个生产线程,他们只负责生产资源;有多个消费者,同样他们只负责消费。但是他们需要满足下面条件:
生产者:只有当资源没有的时候,生产者才开始生产,但是为了防止浪费,每次只能生产指定数量的资源。当生产者生产完足够资源时,就进入睡眠,同时叫醒消费者去消费;
消费者:只有有资源时消费者才会去消费,当然每次消费多少可以自己设置。如果发现资源消费完了,则要马上叫生产者去生产,而消费者马上进入睡眠;
涉及到的知识:线程基础知识、多线程同步、互斥量、条件变量;可以参考: 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;
}
转载地址:http://blog.csdn.net/yuzhihui_no1/article/details/46471663