系统编程_信号量(生产者与消费者信号量模型)

信号量

进化版的互斥锁(1 --> N)

由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。

信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发

主要应用函数:

sem_init 函数

sem_destroy 函数

sem_wait 函数

sem_trywait 函数

sem_timedwait 函数

sem_post 函数

以上 6 个函数的返回值都是:成功返回 0, 失败返回-1,同时设置 errno。(注意,它们没有 pthread 前缀)

sem_t 类型本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节(类似于使用文件描述符)。

sem_t sem; 规定信号量 sem 不能 < 0。头文件 <semaphore.h>

信号量基本操作
sem_wait:

  1. 信号量大于 0,则信号量-- (类比 pthread_mutex_lock)
  2. 信号量等于 0,造成线程阻塞

对应
sem_post:

将信号量++,同时唤醒阻塞在信号量上的线程 (类比 pthread_mutex_unlock)但由于 sem_t 的实现对用户隐藏,所以所谓的++、–操作只能通过函数来实现,而不能直接++、–符号。

信号量的初值,决定了占用信号量的线程的个数。

sem_init 函数: 初始化一个信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);

参 1:sem 信号量
参 2:pshared 取 0 用于线程间;取非 0(一般为 1)用于进程间
参 3:value 指定信号量初值

sem_destroy 函数:
销毁一个信号量
int sem_destroy(sem_t *sem);

sem_wait 函数:
给信号量加锁 –
int sem_wait(sem_t *sem);

sem_post 函数:
给信号量解锁 ++
int sem_post(sem_t *sem);

例:生产者消费者信号量模型

规定: 如果数组中有数据,生产者不能生产,只能阻塞。
如果数组中没有数据,消费者不能消费,只能等待数据。
代码

#include <iostream>
  2 #include <pthread.h>
  3 #include <fcntl.h>
  4 #include <string>
  5 #include <string.h>
  6 #include <semaphore.h>
  7 
  8 using namespace std;
  9 
 10 int deque[5];
 11 
 12 sem_t black_number, peoduct_number;
 13 
 14 void err_pthread(int ret, string str)
 15 {
 16     if(ret != 0)
 17     {
 18         cout<<str<<endl;
 19         cout<<strerror(ret)<<endl;
 20     }
 21 }       
 22         
 23 void *produce(void *arg)
 24 {       
 25     int i = 0;
 26     while(1)
 27     {
 28         sem_wait(&black_number);
 29         deque[i] = rand()%100+1;
 			cout<<"produce : "<<deque[i]<<endl;
 31 
 32         sem_post(&peoduct_number);
 33 
 34         i = (i + 1)%5;
 35 
 36         sleep(rand()%1);
 37     }
 38 
 39     return NULL;
 40 }
 41 
 42 void *consumer(void *arg)
 43 {
 44     int i = 0;
 45     while(1)
 46     {
 47         sem_wait(&peoduct_number);
 48         cout<<"--------consumer : "<<deque[i]<<endl;
 49         deque[i] = 0;
 50         sem_post(&black_number);
 51 
 52         i = (i + 1)%5;
 53 
 54         sleep(rand()%3);
 55     }
 56 
 57     return NULL;
 58 }
 59 int main()
 60 {
 61     pthread_t pid, cid;
 62     srand(time(NULL));
 63     sem_init(&black_number, 0, 5);
 64     sem_init(&peoduct_number, 0, 0);

 66     int ret = pthread_create(&pid, NULL, produce, NULL);
 67     err_pthread(ret, "pthread error");
 68 
 69     ret = pthread_create(&cid, NULL, consumer, NULL);
 70     err_pthread(ret, "pthread error");
 71 
 72     ret = pthread_join(pid, NULL);
 73     err_pthread(ret, "pthread_join error");
 74 
 75     ret = pthread_join(cid, NULL);
 76     err_pthread(ret, "pthread_join error");
 77 
 78     sem_destroy(&black_number);
 79     sem_destroy(&peoduct_number);
 80 
 81     return 0;
 82 }

参考资源
https://www.bilibili.com/video/BV1iJ411S7UA/?p=2&spm_id_from=pageDriver

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值