Linux之posix信号量

今天来讲下POSIX信号量,用于同步操作,达到无冲突的访问共享资源的目的,可以用于线程间同步。

信号量就是一个计数器+等待队列+等待+唤醒

1.信号量的基本接口

1)初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:信号量变量
pshared:0表示线程间共享,非0表示进程间共享(决定用于线程间还是进程间)
value:信号量初始值

2)销毁信号量
int sem_destroy(sem_t *sem);

3)等待信号量
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);

4)发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。 int sem_post(sem_t *sem);

信号量和条件变量的区别:
信号量与条件变量的区别:信号量拥有资源计数的功能,临界资源是否能够操作通过自身技术判断,条件变量是搭配互斥锁一起使用的,信号量还可以实现互斥,计数仅为0/1< font>

2.信号量实现生产者与消费者模型

上一节我用基本队列实现了一个生产者与消费者模型,这节我将用信号量和大小固定的环形
队列再次实现生产者与消费者模型:

实现代码

  1 #include<iostream>
  2 #include<pthread.h>
  3 #include<vector>
  4 #include<semaphore.h>
  5 
  6 //实现线程安全的环形队列,用信号量和线性表实现
  7 //信号量就是一个计数器,具有等待队列+等待+唤醒功能
  8 
  9 class RingQueue
 10 {
 11 public:
 12     RingQueue(int cap = 10):queue(10),capacity(cap)      //构造函数,采用了初始化列表的形式,定义环形队列大小capacity为10
 13             ,write_step(0),read_step(0){
 14         //int sem_init(sem_t *sem, int pshared, unsigned int value);
 15         //sem:信号量变量
 16         //pshared:决定信号量用于线程还是进程
 17         //0为线程   !0为进程
 18         //value:信号量初始计数
 19         sem_init(&data,0,0);
 20         sem_init(&idle,0,cap);
 21         sem_init(&lock,0,1);
 22     }
 23     ~RingQueue(){                         //析构函数
 24         sem_destroy(&data);
 25         sem_destroy(&idle);
 26         sem_destroy(&lock);
 27     }
 28     bool QueuePush(int data){
 29         ProductorWait();                  //因为信号量自带一个计数功能,所以不需要在循环判断,先加一个等待是为了判断是否队列空了,如果先加锁然后却发现满了程序就会卡在productorwait()那里没有解锁。
 30         QueueLock();                     //访问临界资源加锁
 31         queue[write_step] = data;        //放数据
 32         write_step = ((write_step)+1)%capacity;   //写指针要改变
 33         QueueUnlock();                   //访问完毕后解锁,因为锁只是限制临界资源的访问,不限制其他操作
 34         ConsumorWakeUp();                //唤醒消费者
 35         return true;
 36     }
 37     bool QueuePop(int *data){          
 38         ConsumorWait();      //同理先加一个等待是为了判断是否有资源可以取,否则先加锁了,结果发现没有临界资源可以访问,则会卡在consumorwait()那里没有解锁。
 39         QueueLock();
 40         *data = queue[read_step];               //取数据
 41         read_step = ((read_step)+1)%capacity;   //渎指针要改变
 42         QueueUnlock();
 43         ProductorWakeUp();
 44         return true;
 45     }
 46 private:
 47     void QueueLock(){
 48         sem_wait(&lock);
 49     }
 50     void QueueUnlock(){
 51         sem_post(&lock);
 52     }
 53     void ConsumorWait(){
 54         sem_wait(&data);
 55     }
 56     void ConsumorWakeUp(){
 57         sem_post(&data);
 58     }
 59     void ProductorWait(){
 60         sem_wait(&idle);
 61     }
 62     void ProductorWakeUp(){
 63         sem_post(&idle);
 64     }
 65 private:
 66     std::vector<int> queue;
 67     int capacity;
 68     int write_step;
 69     int read_step;
 70     sem_t data;   //代表消费者信号量    
 71     sem_t idle;   //代表生产者信号量
 72     sem_t lock;
 73 };
 74 
 75 void* pth_consumor(void* arg)
 76 {
 77     RingQueue *q = (RingQueue*) arg;
 78     while(1){
 79         int data;
 80         q->QueuePop(&data);
 81         std::cout<<"consumor get data!"<<std::endl;
 82     }
 83     return NULL;
 84 }
 85 
 86 void* pth_productor(void* arg)
 87 {
 88     RingQueue* q = (RingQueue*) arg;
 89     int i=0;
 90     while(1){
 91         q->QueuePush(i);
 92         std::cout<<"productor put data!"<<std::endl;
 93         i++;
 94     }
 95     return NULL;
 96 }
 97 
 98 int main()
 99 {
100     pthread_t ctid[4],ptid[4];
101     int ret,i;
102     RingQueue q;
103     for(i=0;i<4;i++){
104         ret = pthread_create(&ctid[i],NULL,pth_consumor,(void*)&q);
105         if(ret!=0){
106             std::cout<<"consumor not exist!"<<std::endl;
107             return -1;
108         }
109     }
110     for(i=0;i<4;i++){
111         ret = pthread_create(&ptid[i],NULL,pth_productor,(void*)&q);
112         if(ret!=0){
113             std::cout<<"productor not exist!"<<std::endl;
114             return -1;
115         }
116     }
117     for(i=0;i<4;i++){               //线程等待
118         pthread_join(ctid[i],NULL); 
119     }
120     for(i=0;i<4;i++){
121         pthread_join(ptid[i],NULL);
122     }
123     return 0;
124 }

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值