C语言模拟生产者-消费者问题
依然是OS课程实验,在这里写一篇blog记录一下。
0x00 实验目的
探索、理解并掌握操作系统命令解释器的设计原理和实现机制,基于 Linux 内核进行相 应命令解释程序的设计和实现,并在 Linux 操作系统平台上加以测试验证。
0x01 实验环境
系统环境:MAC OS Catalina 10.15.3
虚拟机环境:Parallels desktop 15+Ubuntu 18.04.3 LTS
编程语言:C语言
0x02运行环境
理论上可以在Linux的各个发行版中运行
0x03实现代码
生产者消费者问题还是比较简单的,主要用到了C语言的信号量和线程同步机制。代码注释比较详细,在这里不过多解释,直接给出代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define THREAD_NUM 3 //生产者消费者数量
#define BUF_NUM 8 //缓存区大小
int in = 0; // 生产在者指针
int out = 0; // 消费者指针
int buf[BUF_NUM] = { 0 }; // 缓冲区
sem_t empty; // 空缓存区信号量
sem_t full; // 满缓存区信号量
pthread_mutex_t mutexP; // 生产者互斥信号量
pthread_mutex_t mutexC; // 消费者互斥信号量
void *product(void *args)
{
int i=5; //每个生产者生产5个产品
int *id=(int*)args;
while(i)
{
sem_wait(&empty); //等待空信号量
pthread_mutex_lock(&mutexP); //等待生产者互斥信号量
buf[in]=1; //生产数据放入缓存区,这里用1指代
printf("生产者%d:生产数据放入缓存区%d中!\n",*id,in);
in=(in+1)%BUF_NUM; //指针前进
pthread_mutex_unlock(&mutexP); //释放生产者互斥信号量
sem_post(&full); //释放满缓存区信号量
i--;
}
}
void *customer(void *args)
{
int i=5; //每个消费者者消费5个产品
int *id=(int*)args;
while(i)
{
sem_wait(&full); //等待满信号量
pthread_mutex_lock(&mutexC); //等待消费者互斥信号量
buf[out]=0; //消费数据移出缓存区,这里用0指代
printf("消费者%d:消费数据从缓存区%d中!\n",*id,out);
out=(out+1)%BUF_NUM; //指针前进
pthread_mutex_unlock(&mutexC); //释放消费者互斥信号量
sem_post(&empty); //释放空缓存区信号量
i--;
}
}
int main()
{
pthread_t Ptid[THREAD_NUM]; //生产者标识
pthread_t Ctid[THREAD_NUM]; //消费者标识
int id[THREAD_NUM]={1,2,3}; //生产者消费者编号
int ret[THREAD_NUM];
//初始化信号量
sem_init(&empty, 0, BUF_NUM);
sem_init(&full, 0, 0);
//初始化互斥信号量
pthread_mutex_init(&mutexP, NULL);
pthread_mutex_init(&mutexC, NULL);
for(int i=0;i<THREAD_NUM;i++)
{
ret[i]=pthread_create(&Ptid[i], NULL, product, (void*)&id[i]);
if (ret[i] != 0)
{
printf("生产者%d号线程创建失败! \n", i+1);
exit(0);
}
}
for(int i=0;i<THREAD_NUM;i++)
{
ret[i]=pthread_create(&Ctid[i], NULL, customer, (void*)&id[i]);
if (ret[i] != 0)
{
printf("消费者%d号线程创建失败! \n", i+1);
exit(0);
}
}
for(int i=0;i<THREAD_NUM;i++)
{
pthread_join(Ptid[i],NULL);
pthread_join(Ctid[i],NULL);
}
return 0;
}
0x04 测试结果
下面是当程序运行起来后显示的内容:
从上图可以看出,当程序运行时,首先生产者1开始生产数据并放在缓存区0中,然后是生产者3开始生产,之后消费者2会首先从缓存区0中取出数据,然后后面继续生产和消费,逻辑成立,程序没有问题,实现了生产者和消费者多线程运行的功能!
0x05 后记
之前写多线程大都是用的python和java,倒是的确没有用C语言写过,这次写这个程序,也事先查阅了一些关于C语言多线程和信号量的资料,毕竟C语言还是更接近底层的语言,多学一些总没坏处。程序逻辑还是比较简单的,只不过多线程调试起来比较费力,不过总体情况还可以,过几天把哲学家就餐问题和读者优先/写者优先的读者写者问题也写一下吧。
源码已上传GitHub:源代码
文章的确不错啊https://www.cscnn.com/
想想你的文章写的特别好www.jiwenlaw.com
想想你的文章写的特别好https://www.ea55.com/
看的我热血沸腾啊https://www.237fa.com/