Linux c系统编程多线程之生产者消费者问题
使用条件变量实现生产者-消费者问题:
-
商品使用一个链式队列描述,初始商品个数为8,最大商品个数是10个,不同的商品用不同的随机数区分
-
生产者有3个线程,每个线程每3秒产生一个商品
-
消费者有2个线程,先睡眠5秒,每个线程每1秒消耗一个商品
显示每次生产和消费的商品的随机编号。
思考:1.多线程并发访问造成的资源竞争问题—>可以使用互斥锁进行解决,A线程在访问共享资源的时候先上锁,这是若有其他线程B访问共享资源就会陷入阻塞,直到A访问完毕并且释放锁之后,B线程才能访问。
2.该题目设计两个同步问题:使用条件变量
-
生产 - > 消费
当生产者生产的产品数量达到上限时,这是会陷入等待,需要消费者线程消费之后才能生产
消费 -> 生产
3.虚假唤醒问题: 使用条件wait;
while(number >= 0){
pthread_cond_wait(&cond,&mutex);
}
代码如下:
#include <func.h>
typedef struct node_s{
int val;
struct node_s* next;
}node_t;
typedef struct{
node_t* head;
node_t* tail;
int size;
}Queue;
typedef struct shrerRes_s{
pthread_mutex_t mutex;
pthread_cond_t cond;
Queue* que;
int cnt;
}shareRes_t;
void initQueue(Queue* que);
bool isEmpty(Queue* que);
void pushQueue(Queue* que, int ele);
void popQueue(Queue* que, int* ele);
void printQueue(Queue* que);
void* productor(void* arg){
shareRes_t* sRs = (shareRes_t*)arg;
while(1){
pthread_mutex_lock(&sRs->mutex);
while(sRs->cnt >= 10){
pthread_cond_wait(&sRs->cond,&sRs->mutex);
}
//生产
int id = rand()%100 + 1;
pushQueue(sRs->que,id);
sRs->cnt++;
printf("productor, id:%d\n",id);
printQueue(sRs->que);
pthread_cond_broadcast(&sRs->cond);
pthread_mutex_unlock(&sRs->mutex);
sleep(3);
}
pthread_exit(NULL);
}
void* consumer(void* arg){
sleep(5);
shareRes_t* sRs = (shareRes_t*)arg;
while(1){
pthread_mutex_lock(&sRs->mutex);
while(sRs->cnt <= 0){
pthread_cond_wait(&sRs->cond,&sRs->mutex);
}
//生产
int id;
popQueue(sRs->que,&id);
printf("consumer, id:%d\n",id);
printQueue(sRs->que);
sRs->cnt--;
pthread_cond_broadcast(&sRs->cond);
pthread_mutex_unlock(&sRs->mutex);
sleep(1);
}
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
shareRes_t sRs;
sRs.que = (Queue*)malloc(sizeof(Queue));
pthread_mutex_init(&sRs.mutex,NULL);
pthread_cond_init(&sRs.cond,NULL);
sRs.cnt = 0;
srand(time(NULL));
pthread_t pt1,pt2,pt3;
pthread_t ct1,ct2;
//生产八个产品
for(int i = 0; i < 8; i++){
pushQueue(sRs.que,rand()%100+1);
sRs.cnt++;
}
pthread_create(&pt1,NULL,productor,&sRs);
pthread_create(&pt2,NULL,productor,&sRs);
pthread_create(&pt3,NULL,productor,&sRs);
pthread_create(&ct1,NULL,consumer,&sRs);
pthread_create(&ct2,NULL,consumer,&sRs);
pthread_join(pt1,NULL);
pthread_join(pt2,NULL);
pthread_join(pt3,NULL);
pthread_join(ct1,NULL);
pthread_join(ct2,NULL);
return 0;
}
void initQueue(Queue* que){
que->head = NULL;
que->tail = NULL;
que->size = 0;
}
bool isEmpty(Queue* que){
return que->head == NULL;
}
void pushQueue(Queue* que, int ele){
node_t* newNode = (node_t*)malloc(sizeof(node_t));
if(newNode == NULL){
fprintf(stderr,"%s\n","allocate memary failed\n");
exit(1);
}
newNode->next = NULL;
newNode->val = ele;
if(que->head == NULL){
que->head = que->tail = newNode;
}else{
que->tail->next = newNode;
que->tail = que->tail->next;
}
que->size++;
}
void popQueue(Queue* que, int* ele){
if(isEmpty(que)){
printf("Queue is empty\n");
return;
}
node_t* tmp = que->head;
*ele = tmp->val;
if(que->head == que->tail){
que->head = que->tail = NULL;
}else{
que->head = que->head->next;
}
free(tmp);
que->size--;
}
void printQueue(Queue* que){
node_t* head = que->head;
while(head){
printf("%d ",head->val);
head = head->next;
}
printf("\n");
}