【操作系统】——同步问题之消费者生产者

关于生产者消费者的同步问题,是操作系统中比较经典的问题。在面试的通常会考第一点让你说出生产者消费者模型,第二点会给你该模型的使用场景,然后实现代码。这篇文章就让我们对其了解了解吧~

一、生产者消费者模型描述
两个或者更多的进程(线程)共享同一个缓冲区,其中一个或多个进程(线程)作为“生产者”会不断地向缓冲区中添加数据,另一个或者多个进程(线程)作为“消费者”从缓冲区中取走数据。其模型关注的是以下几点:

  • 生产者和消费者必须互斥的使用缓冲区
  • 缓冲区空时,消费者不能读取数据
  • 缓冲区满时,生产者不能添加数据

二、模型优点
(1)解耦
多了一个缓冲区,把生产者和消费者之间的强耦合解开,变成了生产者和缓冲区,消费者和缓冲区之间的弱耦合。
(2)支持并发
生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据添加到缓冲区,就可以再去生产下一个数据了。而消费者也是一样的,从缓冲区中读取数据,不需要等待生产者。这样,生产者和消费者就可以并发的执行。
(3)支持忙闲不均
生产者只需要将生产的数据添加到缓冲区,缓冲区满了就不生产了。消费者从缓冲区中读取数据,缓冲区空了就不消费了,使得生产者/消费者的处理能力达到一个动态的平衡。

三、关键注意点
(1)假设缓冲区的大小为n(也就是存储单元的个数),它可以被生产者和消费者循环使用。
(2)分别设置两个指针in和out,指向生产者将存放数据的存储单元和消费者将取数据的存储单元,如下图。
在这里插入图片描述
(3) 生产者不能向满缓冲区写数据,消费者不能在空缓冲区中取数据,即必须对生产者和消费者进行同步。另外,如果不进行同步控制,生产者和消费者可能同时进入缓冲区,甚至可能同时读写一个存储单元,将导致执行结果不确定。

四、问题分析
执行流程总结如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
五、代码实现

具体问题场景描述:
假设有一个int型数组 ,有n=10个元素。现在视该数组为缓冲区,创建三个线程作为生产者,没随机几秒向缓冲区写入数据,再创建两个线程作为消费者,每隔几秒从缓冲区取数据并打印。 (随机函数可使用m = rand(), 等待若干秒使用sleep(m))
补充知识点:
(1)sem_t: 信号量的数据类型为结构sem_t,它本质上是一个长整型的数。
(2)函数sem_post(sem_t *sem )用来增加信号量的值。
(3)函数sem_wait(sem_t *sem)被用来阻塞当前线程直到信号量sem的值大于0解除阻塞后将sem的值减一,表明公共资源经使用后减少
(4)#include <pthread.h>//包含线程相关头文件 #include<semaphore.h>//包含信号量相关头文件
(5)pthread_create创建线程函数
(6)pthread_join 线程创建者在子进程运行结束后回收其资源

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<semaphore.h>
#include<string.h>
#include<sys/sem.h>
sem_t s;//互斥信号量,控制对缓冲区的访问
sem_t n;//计数信号量,缓冲区中数据个数
sem_t e;//计数信号量,缓冲区空余单元个数
注意!到底有没有空间写或者有没有数据读,用e,n控制,不必再看in、out
int buffsize[10] = {0};
int  in = 0;//控制缓存区写的位置
int out =0;//控制缓存区取数据的位置
注意!他们的位置是不会发生跳跃的,是一个一个顺序写的,写到末尾再回头从第一个写

void* Producers()
{
      while(1)
       {
              srand(time(NULL));//初始化种子,这个表示每秒递增1
              int data = rand() % 11;
              sem_wait(&e);
              sem_wait(&s);
              buffsize[in] = data;
              printf("%d""%d",in,data);
              in = (in+1) % 10;
              sem_post(&s);
              sem_post(&n);
              sleep(2);
       }
}

void*Consumers()
{
       while(1)
       {
             sem_wait(&n);
              sem_wait(&s);
              printf("%d""%d",out,buffsize[out]);
              buffsize[out] = 0;
              out =(out+1) % 10;
              sem_post(&e);
              sem_post(&s);
              sleep(2);
       }
}

int main()
{
       pthread_t      P1,P2,P3,C1,C2;
       sem_init(&s,0,1);
       sem_init(&s,0,0);
       sem_init(&s,0,10);
       pthread_create(&P1,NULL,Producers,NULL);
       pthread_create(&P2,NULL,Producers,NULL);
       pthread_create(&P3,NULL,Producers,NULL);
       pthread_create(&C1,NULL,Consumers,NULL);
       pthread_create(&C2,NULL,Consumers,NULL);
       pthread_join(P1,NULL);
       pthread_join(P2,NULL);
       pthread_join(P3,NULL);
       pthread_join(C1,NULL);
       pthread_join(C2,NULL);
       sem_destroy(&s);
       sem_destroy(&n);
       sem_destroy(&e);
       exit(0);
}
发布了25 篇原创文章 · 获赞 5 · 访问量 1574

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104291218