linux下实现生产者消费者问题
2014-08-08 16:21
316 查看
生产者(producer)和消费者(consumer)问题是并发处理中最常见的一类问题,是一个多线程同步问题的经典案例。
可以这样描述这个问题,有一个或者多个生产者产生某种类型的数据,并放置在固定大小的缓冲区中,一个消费者从缓冲区中取数据,每次取一项,系统必须保证对缓冲区的重复操作,任何时候,只有一个生产者或者消费者可以访问缓冲区;同时,消费者只能在缓冲区不为空的时候从缓冲区中读数据,生产者只能在缓冲区不为满的时候向缓冲区写入数据。
上面的问题总结起来有两点:
第一是缓冲区的互斥访问问题,任意时刻最多只能有一个线程访问缓冲区,linux下可以使用互斥量pthread_mutex_t对访问缓冲区的临界区代码进行保护。
第二是生产者和消费者对缓冲区访问的同步问题,生产者在缓冲区满时不能向缓冲区中写入数据,同时消费者在缓冲区空时不能读取数据,这里采用两个信号量room_sem和product_sem 来对缓冲区进行同步。
实现代码如下:
需要说明的是下面两条语句的顺序不能改变
可以这样描述这个问题,有一个或者多个生产者产生某种类型的数据,并放置在固定大小的缓冲区中,一个消费者从缓冲区中取数据,每次取一项,系统必须保证对缓冲区的重复操作,任何时候,只有一个生产者或者消费者可以访问缓冲区;同时,消费者只能在缓冲区不为空的时候从缓冲区中读数据,生产者只能在缓冲区不为满的时候向缓冲区写入数据。
上面的问题总结起来有两点:
第一是缓冲区的互斥访问问题,任意时刻最多只能有一个线程访问缓冲区,linux下可以使用互斥量pthread_mutex_t对访问缓冲区的临界区代码进行保护。
第二是生产者和消费者对缓冲区访问的同步问题,生产者在缓冲区满时不能向缓冲区中写入数据,同时消费者在缓冲区空时不能读取数据,这里采用两个信号量room_sem和product_sem 来对缓冲区进行同步。
实现代码如下:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<pthread.h> #include<semaphore.h> #define PRODUCER_NUM 5 //生产者数目 #define CONSUMER_NUM 5 //消费者数目 #define POOL_SIZE 11 //缓冲池大小 int pool[POOL_SIZE]; //缓冲区 int head=0; //缓冲池读取指针 int rear=0; //缓冲池写入指针 sem_t room_sem; //同步信号信号量,表示缓冲区有可用空间 sem_t product_sem; //同步信号量,表示缓冲区有可用产品 pthread_mutex_t mutex; void producer_fun(void *arg) { while (1) { sleep(1); sem_wait(&room_sem); pthread_mutex_lock(&mutex); //生产者往缓冲池中写入数据 pool[rear] = 1; rear = (rear + 1) % POOL_SIZE; printf("producer %d write to pool\n", (int)arg); printf("pool size is %d\n",(rear-head+POOL_SIZE)%POOL_SIZE); pthread_mutex_unlock(&mutex); sem_post(&product_sem); } } void consumer_fun(void *arg) { while (1) { int data; sleep(10); sem_wait(&product_sem); pthread_mutex_lock(&mutex); //消费者从缓冲池读取数据 data = pool[head]; head = (head + 1) % POOL_SIZE; printf("consumer %d read from pool\n", (int)arg); printf("pool size is %d\n",(rear-head+POOL_SIZE)%POOL_SIZE); pthread_mutex_unlock(&mutex); sem_post(&room_sem); } } int main() { pthread_t producer_id[PRODUCER_NUM]; pthread_t consumer_id[CONSUMER_NUM]; pthread_mutex_init(&mutex, NULL); //初始化互斥量 int ret = sem_init(&room_sem, 0, POOL_SIZE-1); //初始化信号量room_sem为缓冲池大小 if (ret != 0) { printf("sem_init error"); exit(0); } ret = sem_init(&product_sem, 0, 0); //初始化信号量product_sem为0,开始时缓冲池中没有数据 if (ret != 0) { printf("sem_init error"); exit(0); } for (int i = 0; i < PRODUCER_NUM; i++) { //创建生产者线程 ret =pthread_create(&producer_id[i], NULL, producer_fun, (void*)i); if (ret != 0) { printf("producer_id error"); exit(0); } //创建消费者线程 ret = pthread_create(&consumer_id[i], NULL, consumer_fun, (void*)i); if (ret != 0) { printf("consumer_id error"); exit(0); } } for(int i=0;i<PRODUCER_NUM;i++) { pthread_join(producer_id[i],NULL); pthread_join(consumer_id[i],NULL); } exit(0); }运行结果:
需要说明的是下面两条语句的顺序不能改变
sem_wait(&room_sem); pthread_mutex_lock(&mutex);,否则,若缓冲区满时,生产者进入临界区后阻塞在sem_wait(&room_sem)语句中,因为生产者未释放互斥锁mutex,导致消费者无法进入临界区,也无法对room_sem执行sem_post操作,生产者线程和消费者线程进入循环等待的境地,从而产生死锁。
相关文章推荐
- Linux C 实现生产者消费者问题
- Linux生产者与消费者的问题实现
- linux下使用线程实现生产者消费者问题
- 生产者-消费者问题实现 (linux下C同步信号量和互斥信号量的应用)
- linux进程内存共享---实现生产者消费者问题
- linux下生产者消费者问题的实现
- Linux下信号量实现进程同步、互斥(生产者消费者问题)
- Linux C 实现生产者消费者问题
- linux 下 条件变量实现生产者消费者问题
- 生产者-消费者问题实现 (linux下C语言)
- 经典同步问题linux下的C实现:生产者-消费者问题,读者-写者问题,哲学家问题
- 经典同步问题linux下的C实现:生产者-消费者问题,读者-写者问题,哲学家问题
- linux下多线程互斥量实现生产者--消费者问题和哲学家就餐问题
- 生产者-消费者问题实现 (linux下C语言)
- Linux下利用信号量函数和共享内存函数和C语言实现生产者消费者问题
- Linux下用条件变量实现多线程间生产者与消费者问题
- 生产者-消费者问题实现 (linux下C语言)----笛风读书笔记系列
- Linux平台下线程同步,实现“生产者消费者问题”
- 生产者与消费者问题(linux下C实现)
- 生产者-消费者问题实现 (linux下C语言)