POSIX信号量和基于环形队列的生产消费模型
1. POSIX信号量
是什么?
描述临界资源有效个数的计数器
为什么?
因为临界资源可以看成多份,不冲突,提高效率
1.1 POSIX信号量接口函数
初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值
销毁信号量
int sem_destroy(sem_t *sem);
等待信号量
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);
//P()这一步也可以形象的理解为你购买电影票,即使没有去看,但是那个位置已经给你预定了,这里的P还是下面的V操作都是带有预定的意思。
发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);
//V()
2. 基于环形队列的生产消费模型
环形队列采用数组模拟,用模运算来模拟环状特性
comsumer:更在意数据,但是如果消费者不受控制,一直读数据,就有可能读到废弃的数据。
productor:更在意空格子,如果生产者不受控制,在继续生产,就会覆盖掉原先的数据。
所以需要生产者和消费者之间能够协同起来(不能读到废弃的数据也不能数据覆盖)
RingQueue.hpp
#pragma once
#include<iostream>
#include<vector>
#include<unistd.h>
#include<semaphore.h>
#define NUM 10
class RingQueue
{
private:
std::vector<int> v;
int max_cap;
sem_t sem_blank;//生产者
sem_t sem_date; //消费者
int c_index;//消费者的索引
int p_index;//生产者的索引
private:
void P(sem_t& s)
{
sem_wait(&s);
}
void V(sem_t& s)
{
sem_post(&s);
}
public:
RingQueue(int _cap = NUM)
:max_cap(_cap)
,v(_cap)
{
sem_init(&sem_blank,0,max_cap);//要初始化哪一个信号量,0表示线程,非0表示进程,要初始化的个数
sem_init(&sem_date,0,0);
c_index = 0;
p_index = 0;
}
~RingQueue()
{
sem_destroy(&sem_blank);
sem_destroy(&sem_date);
c_index = 0;
p_index = 0;
}
//谁来拿,当然是消费者
void Get(int& out)
{
P(sem_date);//--
//消费
out = v[c_index];
c_index++;
c_index %= max_cap;
V(sem_blank);//++
}
void Put(const int& in)
{
P(sem_blank);//相当于预约
//生产
v[p_index] = in;
p_index++;
p_index %= max_cap;
V(sem_date);
}
};
main.cc
#include"RingQueue.hpp"
void *comsumer(void *ring_queue)
{
RingQueue* rq = (RingQueue*)ring_queue;
while(1)
{
int date = 0;
rq->Get(date);
std::cout<< "comsumer done ... #" << date<<std::endl;
}
}
//让生产者不断的放100-110之间的数
void *productor(void *ring_queue)
{
RingQueue* rq = (RingQueue*)ring_queue;
int count = 100;
while(1)
{
rq->Put(count);
count++;
if(count>110)
{
count = 100;
}
std::cout<<"productor done ..."<<std::endl;
}
}
int main()
{
pthread_t c,p;
RingQueue* rq = new RingQueue();
pthread_create(&c,nullptr,comsumer,rq);
pthread_create(&p,nullptr,productor,rq);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
delete rq;
return 0;
}
第一种情况:让消费者慢,生产者会在一瞬间将队列生产满,然后就会进入到,消费一个,生产一个的过程。
第二种情况:让生产者慢,就会出现生产一个数据,然后消费一个数据。
上面的是一个单生产者单消费者的模式,那么如果想要多生产者多消费者需要咋办呢?
那么此时就还需要在维护2种关系,生产者和生产者、消费者和消费者之间的关系,需要在定义两把锁,让生产者之间相互先竞争,胜出的将去队列中放数据。消费者之间也要先竞争,胜出的将去队列中消耗数据。