Linux的POSIX信号量和生产消费模型的环形队列实现
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()
发布信号量:
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加 1。
int sem_post(sem_t *sem);//V()
基于环形队列的生产消费模型
对于消费者,关心的是数据资源数量;而对于生产者,我们则关心的是空间大小。因此,对这两个数据写成信号量data_sem,space_sem(两者加起来等于N)。
信号量本身就是判断条件,有资源就可以申请成功,具有原子性。
//RingQueue.hpp
#include<iostream>
#include<pthread.h>
#include<vector>
#include<string>
#include<semaphore.h>
using namespace std;
template<typename T>
class RingQueue
{
public:RingQueue(int max_cap):max_cap(max_cap),c_step(0),p_step(0){sem_init(&data_sem, 0, 0);sem_init(&space_sem, 0, max_cap);_ringqueue.resize(max_cap);pthread_mutex_init(&c, nullptr);pthread_mutex_init(&p, nullptr);}void P(sem_t& t){sem_wait(&t);}void V(sem_t& t){sem_post(&t);}void Push(const T& in){P(space_sem);//满了就等着吧pthread_mutex_lock(&p);_ringqueue[p_step] = in;p_step++;p_step %= max_cap;V(data_sem);pthread_mutex_unlock(&p);}void Pop(T* out){P(data_sem);//没了就等着吧pthread_mutex_lock(&c);//类似于得到票后竞争锁*out = _ringqueue[c_step];c_step++;c_step %= max_cap;V(space_sem);pthread_mutex_unlock(&c);}~RingQueue(){sem_destroy(&data_sem);sem_destroy(&space_sem);}private:vector<T> _ringqueue;int max_cap;int c_step;int p_step;sem_t data_sem; //数据量sem_t space_sem; //剩余容量pthread_mutex_t c, p;
};
#include "RingQueue.hpp"
#include<ctime>
#include<unistd.h>
void* Prouductor(void* args)
{RingQueue<int> *rq = static_cast<RingQueue<int>*>(args);while(1){int data = rand() % 10 + 1;rq->Push(data);cout << "Productor:" << data << endl;}
}
void* Consumer(void* args)
{RingQueue<int> *rq = static_cast<RingQueue<int>*>(args);while(1){int data;rq->Pop(&data);cout << "Consumer:" << data << endl;sleep(1);}
}
int main()
{srand(time(nullptr));RingQueue<int> rq(10);pthread_t _c1, _p1,_c2,_p2,_c3,_c4;pthread_create(&_c1, nullptr, Consumer, &rq);pthread_create(&_p2, nullptr, Prouductor, &rq);pthread_create(&_p1, nullptr, Prouductor, &rq);pthread_create(&_c2, nullptr, Consumer, &rq);pthread_create(&_c3, nullptr, Consumer, &rq);pthread_create(&_c4, nullptr, Consumer, &rq);pthread_join(_c1,nullptr);pthread_join(_p1,nullptr);return 0;
}