1. 生产者消费者问题(producer-consumer),有限缓冲,多线程同步。生产者线程和消费者线程共享固定大小缓冲区。
2. 关键是保证生产者不会再缓冲区满时加入数据,消费者不会在缓冲区空时消耗数据。
3. 解决办法:让生产者在缓冲区满时休眠,等下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒。同样,让消费者在缓冲区空时进入休眠,等到生产者生产数据后再唤醒。
4. 通常采用进程间通信的方法(信号灯法)
#include<iostream>
#include<unistd.h> //需要用到sleep()
#include<pthread.h> //线程库
#include<stdlib.h> //生成随机数rand()需要此头文件
#include<semaphore.h> //需要用到信号量
#define BUFFER_SIZE 10 //缓冲区存储单元设定为10
#define PRODUCER_NUM 6 //设定6个生产者
#define CONSUMER_NUM 6 //设定6个消费者
using namespace std;
typedef int buffer_item;
buffer_item buffer[BUFFER_SIZE]={0};//定义缓冲区每个存储单元都为默认值0
int in = 0 , out = 0;
pthread_mutex_t mutex;//互斥锁
sem_t empty; //信号量的数据类型为结构sem_t,它本质上是一个长整型的数
sem_t full;
//填充数据
void insert_item(buffer_item item){
buffer[in]=item;
in=(in+1)%BUFFER_SIZE;//取余的目的是使缓存区相当于一个环形的
}
//移除数据
void remove_item(buffer_item* item){
*item=buffer[out];
buffer[out]=0;//取走数据后缓存单元复位
out=(out+1)%BUFFER_SIZE;
}
//生产者
void *producer(void* param){
buffer_item item;
pthread_t tid=pthread_self();
while(1){
sleep(2);
item =1+(10.0*rand()/(RAND_MAX+1.0));//产生1-10的随机数
sem_wait(&empty); //若empty大于0,继续执行,减1;若empty为0,等待其它线程增加了这个值使它不再是0为止
pthread_mutex_lock(&mutex);
insert_item(item);
pthread_mutex_unlock(&mutex);
sem_post(&full);
cout<<"线程id为: "<<tid<<" .....生产者.....在"<<in<<"号缓冲单元中生产了数据:"<<item<<endl;
}
}
//消费者
void *consumer(void* param){
buffer_item item;
pthread_t tid = pthread_self();
while(1){
sleep(2);
sem_wait(&full);
pthread_mutex_lock(&mutex);
remove_item(&item);
pthread_mutex_unlock(&mutex);
sem_post(&empty);
cout<<"线程id为: "<<tid<<" 的消费者在"<<out<<"号缓冲单元上消耗了数据:"<<item<<endl;
}
}
int main(){
pthread_t producerid[PRODUCER_NUM];
pthread_t consumerid[CONSUMER_NUM];
pthread_mutex_init(&mutex , NULL); //初始化互斥锁
pthread_attr_t attr;
pthread_attr_init(&attr);//初始化线程属性
sem_init(&empty , 0 , BUFFER_SIZE);//初始化信号量,初始值为BUFFER_SIZE,中间的参数0代表进程内的线程共享
sem_init(&full , 0 , 0);
int i;
for(i=0 ; i<PRODUCER_NUM ; i++)
pthread_create(&producerid[i] ,&attr ,producer , NULL);
for(i=0 ; i<CONSUMER_NUM ; i++)
pthread_create(&consumerid[i] , &attr ,consumer ,NULL);
for(i = 0 ; i<PRODUCER_NUM ; i++)
pthread_join(producerid[i],NULL);
for(i = 0 ; i<CONSUMER_NUM ;i++)
pthread_join(consumerid[i] ,NULL);
return 0;
}