Linux|【Linux】—— 基于信号量的生产者消费者模型

信号量 【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

    推荐阅读