信号量
POSIX信号量和SystemV信号量作⽤相同,都是⽤于同步操作,达到⽆冲突的访问共享资源⽬的。但POSIX可以⽤于线程间同步。
信号量本质是一个计数器,本质是对资源的预定机制
多线程的使用场景:
1.将目标资源整体使用【mutex+2元信号量】1.将目标资源整体使用【mutex+2元信号量】
2.将目标资源按照不同的块分批使用[信号量]
#include
#include
#include
namespace SemModule{
class Sem{
public:
Sem(unsigned int value=1){
sem_init(&sem_,0,value);
}
~Sem(){
sem_destroy(&sem_);
}
void P(){
sem_wait(&sem_);//原子操作
}
void V(){
sem_post(&sem_);
}
private:
sem_t sem_;
};
}
接口介绍:
初始化信号量 :
#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); //P()
发布信号量
功能:发布信号量,表⽰资源使⽤完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);//V()
下面我们先基于几个函数去封装一个信号量
下面我以一个例子去带领大家了解信号量
基于环形队列的生产者消费者模型:
约定1:空,生产者先运行
约定2:满,消费者先运行
约定3:生产者不能把消费者套一个圈以上
约定4:消费者,不能超过生产者

#pragma once
#include
#include"Sem.hpp"
static const int gcap=5;
using namespace SemModule;
template
class RingQueue {
private:
std::vector_rq;
int _cap;
Sem _blank_sem;//表示空的资源
Sem _data_sem;//表示数据的资源
int _p_step;//消费者位置
int _c_step;//生产者位置
public:
RingQueue(int size = gcap)
: _rq(size),
_cap(size),
_blank_sem(size), // 空位一开始是满的
_data_sem(0), // 数据一开始是空的
_p_step(0),
_c_step(0) {}
void Enqueue(const T& in) {
_blank_sem.P(); // 申请空位
_rq[_p_step] = in;
_p_step = (_p_step + 1) % _cap;
_data_sem.V(); // 释放数据
}
void Pop(T& out) {
_data_sem.P(); // 申请数据
out = _rq[_c_step];
_c_step = (_c_step + 1) % _cap;
_blank_sem.V(); // 释放空位
}
};
总结:如果资源可以拆分,你可以考虑sem
如果资源是整体使用的,你就使用mutex
用通俗易懂的话来说:
信号量(semaphore)就是内核(或库)帮你保管的一个“非负整数计数器”+“睡眠/唤醒”机制;P 操作把计数器减 1,如果结果 <0 就让调用者睡进去;V 操作把计数器加 1,如果结果 ≤0 就拉一个睡着的人起来。
评论
还没有任何评论,你来说两句吧!