文章目录
- 前言
- 一、怎样的环形队列?
- 二、什么是信号量
- 三、使用步骤
- 信号量的接口函数
- 1. sem_init
- 2.sem_destroy
- 3.sem_wait
- 4.sem_post
- 环形队列的设计
- 测试用例
前言
之前我们使用互斥锁和条件变量实现过一个生产者消费者模型,那么那个生产消费者模型具有一个缺点那就是只能串形生产与消费。
在某些环境与需求下,我们可以拥有比较大的数据空间,且我们的数据是批次分布在该空间中,我们是否可以让生产与消费并行呢?
通过环形队列我们其实是可以实现的,并且我们本次学习尝试学习认识和如何使用信号量。
一、怎样的环形队列?
这里我们通过例如vector的数组来模拟出环形队列,通过下标%vector.size(),就可以模拟出环形队列。
二、什么是信号量
信号量的本质其实就是一个计数器,他分别具有P操作和V操作,其中P操作可以简单的理解为计数器–,V操作可以简单的理解为计数器++。
而他最重要的就在于信号量的接口操作函数都是原子性的,是线程安全的。
在本次的生产消费者模型中,就充当着可用空间计数和有效数据计数。
三、使用步骤
信号量的接口函数
1. sem_init
该函数用于初始化信号量,其中参数pshared若为0,则不在线程之间共享,参数value则为信号量计数器的初始计数。
2.sem_destroy
销毁信号量。
3.sem_wait
代表着信号量的P操作,也就是让该信号量计数器–。
4.sem_post
代表着信号量的V操作,也就是让该信号量计数器++。
我们再把信号量进行包装一下
#include<semaphore.h>
class Sem{
public:
Sem(unsigned int value)
{
sem_init(&_sem,0,value);
}
void p()
{
sem_wait(&_sem);
}
void v()
{
sem_post(&_sem);
}
~Sem()
{
sem_destroy(&_sem);
}
private:
sem_t _sem;
};
环形队列的设计
#include<iostream>
#include<vector>
#include"semaphore.hpp"
#define DEFAULT_NUM 5
template<class T>
class ringQueue{
public:
ringQueue(int default_num = DEFAULT_NUM)
:_queue(default_num)
,c_step(0)
,p_step(0)
,data_sem(0)
,space_sem(default_num)
{}
void push(T& data)
{
space_sem.p();
_queue[p_step++] = data;
p_step %= _queue.size();
data_sem.v();
}
void pop(T* data)
{
data_sem.p();
*data = _queue[c_step++];
c_step %= _queue.size();
space_sem.v();
}
private:
std::vector<T> _queue;
int c_step;
int p_step;
Sem data_sem;
Sem space_sem;
};
测试用例
#include"ringQueue.hpp"
#include<time.h>
#include<stdlib.h>
#include<unistd.h>
void* productor(void* args)
{
ringQueue<int>* ring_queue = (ringQueue<int>*)args;
while(1)
{
int data = rand() % 100 + 1;
ring_queue->push(data);
std::cout << "生产者已生产数据: " << data << std::endl;
//sleep(1);
}
}
void* consumer(void* args)
{
ringQueue<int>* ring_queue = (ringQueue<int>*)args;
while(1)
{
int data;
ring_queue->pop(&data);
std::cout << "消费者已消费数据: " << data << std::endl;
sleep(1);
}
}
int main()
{
srand((size_t)time(nullptr)^ getpid());
ringQueue<int> ring;
pthread_t p1;
pthread_t p2;
pthread_create(&p1,nullptr,productor,(void*)(&ring));
pthread_create(&p2,nullptr,consumer,(void*)(&ring));
pthread_join(p1,nullptr);
pthread_join(p2,nullptr);
return 0;
}