linux中的生产者-消费者模型(C语言编写、gcc编译)
该模型使用的都是基本的线程控制原语,包括线程的创建、线程回收、线程分离等。
在保持线程同步上使用的是互斥锁和条件变量。
用链表存储生产出来的任务,生产者添加链表节点(使用的头插法),消费者摘除节点,基本模拟了生产者-消费者的思想行为。
该模型实现思路较为简单,仅供学习线程基础以及线程同步的新手参考,有什么问题,欢迎下方留言!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
struct food{//定义链表的内部元素
int num;
struct food* next;
};
struct food* head = NULL;
void* producer(void* arg){//生产者线程
int i = 0;
while(1){
struct food* node = (struct food*)malloc(sizeof(struct food));//给要添加的节点申请空间
node->num = i++;
pthread_mutex_lock(&mutex);
node->next = head;//使用头插法添加节点
head = node;
pthread_mutex_unlock(&mutex);
printf("生产者生产数据node->num=%d\n",node->num);
pthread_cond_broadcast(&cond);//任务生产完毕,唤醒阻塞在条件变量上的线程
usleep(rand()%10*10000);//为了看到效果,设置了一个随机的延时,单位是微秒
}
return NULL;
}
void* consumer(void* arg){
while(1){
pthread_mutex_lock(&mutex);
while(head == NULL){//此处特别强调while一定要是while,不能是if,如果阻塞在加锁上的话,恰好链表没有节点,
//下面再摘除的时候就会出现段错误,所以要循环判断链表是否为空
pthread_cond_wait(&cond,&mutex);//阻塞等待条件变量满足,释放已掌握的互斥锁,当被唤醒时,会解除阻塞重新申请获取互斥锁
}
struct food* node = head;
head = head->next;//摘除头部节点
printf("消费者消费node->num=%d\n",node->num);
pthread_mutex_unlock(&mutex);
free(node);
usleep(rand()%10*10000);//同样设置了一个随机的延时
}
return NULL;
}
int main(int argc, char* argv[])
{
srand(time(NULL));//设置一个随机种子
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,producer,NULL);//创建线程,执行producer任务
pthread_create(&tid2,NULL,consumer,NULL);//创建了很多的消费者线程,执行consumer任务
pthread_detach(tid2);//设置线程分离
pthread_create(&tid2,NULL,consumer,NULL);
pthread_detach(tid2);
pthread_create(&tid2,NULL,consumer,NULL);
pthread_detach(tid2);
pthread_create(&tid2,NULL,consumer,NULL);
pthread_detach(tid2);
pthread_create(&tid2,NULL,consumer,NULL);
pthread_detach(tid2);
pthread_mutex_init(&mutex,NULL);//初始化互斥锁
pthread_cond_init(&cond,NULL);//初始化条件变量
pthread_join(tid1,NULL);//回收线程
pthread_mutex_destroy(&mutex);//销毁互斥锁
pthread_cond_destroy(&cond);//销毁条件变量
pthread_exit(NULL);
}