信号量 【Linux|【Linux】—— 基于信号量的生产者消费者模型】前面我们在基于阻塞队列的生产者消费者模型 今天我们来看一下基于信号量的生产者消费者模型,也可以说是基于环形队列的。
POSIX信号量
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步
初始化信号量
#include
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);
发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);
基于环形队列的生产者消费者模型
- 环形队列采用数组模拟,用模运算来模拟环状特性
- 环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态
- 但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程
- 简单的总结一句话就是,你不能超过我,我不能把你套个圈,这里你是消费者,我是生产者
- ring.hpp
#ifndef __RING_HPP__
#define __RING_HPP__#include
#include
#include #include
#include #define NUM 32using namespace std;
class Ring{
private:
int circle[NUM];
//环形队列
int cap;
//信号量的容量
int c_step;
//消费者下标
int p_step;
//生产者下标
sem_t sem_data;
//消费者可以消费的数据
sem_t sem_blank;
//生产者可以生产的位置void P(sem_t &s)
{
sem_wait(&s);
}
void V(sem_t &s)
{
sem_post(&s);
}
public:
Ring():cap(NUM)
{
c_step = p_step = 0;
sem_init(&sem_data,0,0);
sem_init(&sem_blank,0,NUM);
}//消费者调用该接口进行消费
void GetData(int& out)
{
P(sem_data);
//消费者申请数据资源消费
out = circle[c_step];
//消费者从环形队列中取数据
c_step++;
V(sem_blank);
//消费者增加空间
c_step %= cap;
//当走到最后时重新置为0
}
//生产者调用该接口进行生产
void PutData(const int& in)
{
P(sem_blank);
//生产者申请空间生产
circle[p_step] = in;
//往环形队列中插入数据
p_step++;
//下标++
V(sem_data);
//生产者增加数据
p_step %= cap;
//因为是环形队列,当走到下标最后时将它重置为0
}~Ring()
{
sem_destroy(&sem_data);
sem_destroy(&sem_blank);
}
};
#endif
- ring.cc
#include "ring.hpp"
#include void* consumer(void* arg)
{
Ring* r = (Ring*)arg;
int data;
for(;
;
){
r->GetData(data);
cout << "consumer data:"<< data <PutData(data);
cout << "product data:"<< data <
- Makefile
ring:ring.cc
g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
rm -f ring
推荐阅读
- Linux|【Linux】生产者消费者模型
- Linux|Linux生产者消费者模型
- 程序员宝贵经验集|代码调不通,OJ题不会做(寻求帮助,学会提问-《提问的智慧》)
- 操作系统|实验一 Linux基本操作
- Linux|Linux基本操作
- 校招|校招 --阶段一 系统编程】基于进程控制的实现简单的shell
- Linux|Shell运行原理和Linux权限
- Linux|【Linux】Shell运行原理及Linux权限的概念