POSIX信号量(基于环形队列的生产消费模型)


POSIX信号量

是什么?

信号量(也叫信号灯),本质是一个在描述临界资源中,有效资源个数的计数器。

如果把临界区划分成多个块儿,那么多个线程可以同时进入临界区访问不同的块。
之前的锁,是我们认为临界资源只有一块。

信号量可以保证让多个线程同时进入临界区,访问临界资源的不同块。

申请信号量,把计数器--叫做P操作;释放信号量,计数器++叫做V操作。

要保证所有的线程都得看到信号量,所以信号量本身就是临界资源,因此得保证它的安全。
因此PV操作一定是原子的。

信号量的意义?

临界资源可以划分成多块。
这样就可以并行的访问临界资源,提高效率。

怎么用?

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源的目的。 但POSIX可以用于线程间同步。

  • 初始化信号量
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); 

pshared:0表示线程间共享,非零表示进程间共享
value:信号量初始值

  • 销毁信号量
int sem_destroy(sem_t *sem); 
  • 等待信号量 - P操作:会将信号量的值减1
int sem_wait(sem_t *sem);  
  • 发布信号量 - V操作:会将信号量的值加1
int sem_post(sem_t *sem); 

基于环形队列的生产消费模型

环形队列可以抽象成数组,用模运算来模拟环状特性。
POSIX信号量(基于环形队列的生产消费模型)
生产者和消费者不指向同一个位置时,队列不满不空;而指向同一个位置时,队列是满或空的状态。

也就是说,下标不同时,它们并行(同步);相同时,它们串行。(互斥)

该模型用信号量维持了生产者和消费者的同步与互斥。

  • RingQueue.hpp
#pragma once  #include <iostream> #include <vector> #include <unistd.h> #include <semaphore.h>  #define NUM 10  class RingQueue{     private:         void P(sem_t &s) // 引用         {             sem_wait(&s); // 取地址         }         void V(sem_t &s)         {             sem_post(&s);         }     public:         RingQueue(int _cap = NUM):max_cap(_cap), v(_cap)         {             sem_init(&sem_space, 0, max_cap); // 0 代表线程间共享,max_cap信号量初始值             sem_init(&sem_data, 0, 0); // 数据资源最初为0             c_index = 0;// 默认消费者从0开始走             p_index = 0;// 默认生产者从0开始走         }          void Put(const int &in)         {             P(sem_space); // 生产者,申请格子资源             v[p_index] = in; // 生产             p_index++;             p_index %= max_cap;             V(sem_data); // 多了一份数据资源         }         void Get(int &out)         {             P(sem_data); // 消费者,申请数据资源             out = v[c_index]; // 消费             c_index++;             c_index %= max_cap;             V(sem_space); // 消费完就多了一份格子资源         }         ~RingQueue()         {             sem_destroy(&sem_space);             sem_destroy(&sem_data);             c_index = 0;             p_index = 0;         }     private:         int max_cap;         std::vector<int> v;         sem_t sem_space; // 生产者关心的格子资源         sem_t sem_data;  // 消费者关心的数据资源          int c_index;  // 决定了它使用临界资源的哪一份         int p_index; };  
  • main.cc
#include"RingQueue.hpp"  void* producer(void* ring_queue) {     RingQueue* rq = (RingQueue*)ring_queue;      while(true)     {         int count = rand()%100 + 1;         sleep(1);         rq->Put(count); //生产         std::cout<< "producer is producing" << std::endl;     } } void* consumer(void* ring_queue) {     RingQueue* rq = (RingQueue*)ring_queue;     while(true)     {         int data = 0;         rq->Get(data); // 消费         std::cout<< "consumer data: #" << data << std::endl;     } }  int main() {     pthread_t p,c;     RingQueue *rq = new RingQueue();      pthread_create(&p, nullptr, producer, rq);     pthread_create(&c, nullptr, consumer, rq);      pthread_join(p, nullptr);     pthread_join(c, nullptr);      delete rq;     return 0; } 
  • Makefile
testRingQueue:main.cc 	g++ $^ -o $@ -std=c++11 -lpthread .PHONY:clean clean: 	rm -f testRingQueue 

版权声明:玥玥 发表于 2021-04-29 8:34:55。
转载请注明:POSIX信号量(基于环形队列的生产消费模型) | 女黑客导航