Linux信号量机制(生产者消费者)

该程序为Linux信号量机制实现程序,主要模拟了一般的生产者-消费者问题。(生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有已用的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
 
#define N 5   // 消费者或者生产者的数目
#define M 10 // 缓冲数目
//int M=10;
int in = 0; // 生产者放置产品的位置
int out = 0; // 消费者取产品的位置
 
int buff[M] = { 0 }; // 缓冲初始化为0,开始时没有产品
 
sem_t empty_sem; // 同步信号量,当满了时阻止生产者放产品
sem_t full_sem; // 同步信号量,当没产品时阻止消费者消费
pthread_mutex_t mutex; // 互斥信号量,一次只有一个线程访问缓冲
 
int product_id = 0; //生产者id
int prochase_id = 0; //消费者id
//信号处理函数
void Handlesignal(int signo){
    printf("程序退出\n",signo);
    exit(0);
}
/* 打印缓冲情况 */
void print() {
       int i;
       printf("产品队列为");
       for(i = 0; i < M; i++)
              printf("%d", buff[i]);
       printf("\n");
}
 
/* 生产者方法 */
void *product() {
       int id = ++product_id;
       while(1) {//重复进行
              //用sleep的数量可以调节生产和消费的速度,便于观察
              sleep(2);
 
              sem_wait(&empty_sem);
              pthread_mutex_lock(&mutex);
 
              in= in % M;
              printf("生产者%d在产品队列中放入第%d个产品\t",id, in);
 
              buff[in]= 1;
              print();
              ++in;
 
              pthread_mutex_unlock(&mutex);
              sem_post(&full_sem);
       }
}
 
/* 消费者方法 */
void *prochase() {
       int id = ++prochase_id;
       while(1) {//重复进行
              //用sleep的数量可以调节生产和消费的速度,便于观察
              sleep(5);
 
              sem_wait(&full_sem);
              pthread_mutex_lock(&mutex);
 
              out= out % M;
              printf("消费者%d从产品队列中取出第%d个产品\t",id, out);
 
              buff[out]= 0;
              print();
              ++out;
 
              pthread_mutex_unlock(&mutex);
              sem_post(&empty_sem);
       }
}
 
int main() {
       printf("生产者和消费者数目都为5,产品缓冲为10,生产者每2秒生产一个产品,消费者每5秒消费一个产品,Ctrl+退出程序\n");
       pthread_t id1[N];
       pthread_t id2[N];
       int i;
       int ret[N];
       //结束程序
    if(signal(SIGINT,Handlesignal)==SIG_ERR){//按ctrl+C产生SIGINT信号
    printf("信号安装出错\n");
    }
// 初始化同步信号量
       int ini1 = sem_init(&empty_sem, 0, M);//产品队列缓冲同步
       int ini2 = sem_init(&full_sem, 0, 0);//线程运行同步
       if(ini1 && ini2 != 0) {
              printf("信号量初始化失败!\n");
              exit(1);
       }
//初始化互斥信号量
       int ini3 = pthread_mutex_init(&mutex, NULL);
       if(ini3 != 0) {
              printf("线程同步初始化失败!\n");
              exit(1);
       }
// 创建N个生产者线程
       for(i = 0; i < N; i++) {
              ret[i]= pthread_create(&id1[i], NULL, product, (void *) (&i));
              if(ret[i] != 0) {
                     printf("生产者%d线程创建失败!\n", i);
                     exit(1);
              }
       }
//创建N个消费者线程
       for(i = 0; i < N; i++) {
              ret[i]= pthread_create(&id2[i], NULL, prochase, NULL);
              if(ret[i] != 0) {
                     printf("消费者%d线程创建失败!\n", i);
                     exit(1);
              }
       }
//等待线程销毁
       for(i = 0; i < N; i++) {
              pthread_join(id1[i], NULL);
              pthread_join(id2[i],NULL);
       }
       exit(0);
}

在linux下编译语句为:gcc -o producer_consumer.out producer_consumer.c -lpthread

这个是因为pthread并非Linux系统的默认库,编译时注意加上-lpthread参数,以调用链接库

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验题目: 生产者消费者(综合性实验) 实验环境: C语言编译器 实验内容: ① 由用户指定要产生的进程及其类别,存入进入就绪队列。    ② 调度程序从就绪队列提取一个就绪进程运行。如果申请的资源被阻塞则进入相应的等待队列,调度程序调度就绪队列的下一个进程。进程运行结束时,会检查对应的等待队列,激活队列的进程进入就绪队列。运行结束的进程进入over链表。重复这一过程直至就绪队列为空。    ③ 程序询问是否要继续?如果要转直①开始执行,否则退出程序。 实验目的: 通过实验模拟生产者消费者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。 实验要求: 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程类型标号、进程系统号、进程状态、进程产品(字符)、进程链指针等等。 系统开辟了一个缓冲区,大小由buffersize指定。 程序有三个链队列,一个链表。一个就绪队列(ready),两个等待队列:生产者等待队列(producer);消费者队列(consumer)。一个链表(over),用于收集已经运行结束的进程 本程序通过函数模拟信号量的操作。 参考书目: 1)徐甲同等编,计算机操作系统教程,西安电子科技大学出版社 2)Andrew S. Tanenbaum著,陈向群,马红兵译. 现代操作系统(第2版). 机械工业出版社 3)Abranham Silberschatz, Peter Baer Galvin, Greg Gagne著. 郑扣根译. 操作系统概念(第2版). 高等教育出版社 4)张尧学编著. 计算机操作系统教程(第2版)习题解答与实验指导. 清华大学出版社 实验报告要求: (1) 每位同学交一份电子版本的实验报告,上传到202.204.125.21服务器。 (2) 文件名格式为班级、学号加上个人姓名,例如: 电子04-1-040824101**.doc   表示电子04-1班学号为040824101号的**同学的实验报告。 (3) 实验报告内容的开始处要列出实验的目的,实验环境、实验内容等的说明,报告要附上程序代码,并对实验过程进行说明。 基本数据结构: PCB* readyhead=NULL, * readytail=NULL; // 就绪队列 PCB* consumerhead=NULL, * consumertail=NULL; // 消费者队列 PCB* producerhead=NULL, * producertail=NULL; // 生产者队列 over=(PCB*)malloc(sizeof(PCB)); // over链表 int productnum=0; //产品数量 int full=0, empty=buffersize; // semaphore char buffer[buffersize]; // 缓冲区 int bufferpoint=0; // 缓冲区指针 struct pcb { /* 定义进程控制块PCB */ int flag; // flag=1 denote producer; flag=2 denote consumer; int numlabel; char product; char state; struct pcb * processlink; …… }; processproc( )--- 给PCB分配内存。产生相应的的进程:输入1为生产者进程;输入2为消费者进程,并把这些进程放入就绪队列。 waitempty( )--- 如果缓冲区满,该进程进入生产者等待队列;linkqueue(exe,&producertail); // 把就绪队列里的进程放入生产者队列的尾部 void signalempty() bool waitfull() void signalfull() void producerrun() void comsuerrun() void main() { processproc(); element=hasElement(readyhead); while(element){ exe=getq(readyhead,&readytail); printf("进程%d申请运行,它是一个",exe->numlabel); exe->flag==1? printf("生产者\n"):printf("消费者\n"); if(exe->flag==1) producerrun();
Linux 信号量是一种进程间通信机制,用于同步进程间的操作。在生产者消费者问题,可以使用信号量实现生产者消费者之间的同步。 具体实现方法如下: 1. 定义两个信号量一个用于表示缓冲区可用的空间数量,另一个用于表示缓冲区已经存储的数据数量。 2. 生产者在向缓冲区写入数据之前,需要先获取空闲空间的信号量。如果当前可用空间数量为 0,则生产者需要等待,直到有空闲空间可用。 3. 生产者写入数据后,需要释放已经存储的数据数量的信号量,表示缓冲区已经存储了新的数据。 4. 消费者在从缓冲区读取数据之前,需要先获取已经存储的数据数量的信号量。如果当前已经存储的数据数量为 0,则消费者需要等待,直到有数据可读。 5. 消费者读取数据后,需要释放空闲空间的信号量,表示缓冲区有了新的空闲空间。 下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int in = 0, out = 0; sem_t empty, full; pthread_mutex_t mutex; void *producer(void *arg) { int item = 0; while (1) { // 等待空闲空间 sem_wait(&empty); pthread_mutex_lock(&mutex); // 生产数据 item++; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; printf("Producer produced item %d\n", item); pthread_mutex_unlock(&mutex); // 释放已经存储的数据数量信号量 sem_post(&full); sleep(1); } } void *consumer(void *arg) { int item; while (1) { // 等待有数据可读 sem_wait(&full); pthread_mutex_lock(&mutex); // 消费数据 item = buffer[out]; out = (out + 1) % BUFFER_SIZE; printf("Consumer consumed item %d\n", item); pthread_mutex_unlock(&mutex); // 释放空闲空间信号量 sem_post(&empty); sleep(2); } } int main() { pthread_t tid1, tid2; sem_init(&empty, 0, BUFFER_SIZE); sem_init(&full, 0, 0); pthread_mutex_init(&mutex, NULL); pthread_create(&tid1, NULL, producer, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(&empty); sem_destroy(&full); pthread_mutex_destroy(&mutex); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值