【Linux系统】信号量实现同步和互斥

一.回顾

在这之前已经讲解了System V版本的信号量,主要内容为以下3点:

  1. 信号量本质是一把计数器
  2. 申请信号量本质就是预订资源
  3. PV操作(申请和释放)是原子的

今天我们要学习的是POSIX版本的信号量,以上三点同样遵循

二.信号量VS互斥锁

1.联系:

信号量和互斥锁都是保护公共资源的手段,想要通过临界区访问临界资源,必须先要申请信号量或者互斥锁。并且计数器为1的信号量功能等同于互斥锁。

2.区别:

  1. 互斥锁将公共资源当成一个整体使用,信号量可以实现把公共资源分成若干区域,给不同的执行流同时使用。
  2. 申请锁成功,线程进来后一般还要使用如if这样的判断语句,来检测资源是否就绪,如果没有就绪,为了并发的高效,还需要等待条件变量。(进电影院之后再现场买票)。但是申请信号量成功,线程进来之后无需判断资源是否就绪,因为只要申请信号量成功,说明一定有资源分配给你,并且这份资源只有你自己能访问。(提前买电影票)
  3. 互斥锁在信号量都在pthread库中,不过互斥锁声明在<pthread.h>头文件,信号量声明在<semaphore.h>中

线程使用信号量流程:

申请信号量->访问指定区域->释放信号量

三.信号量用法

1.初始化信号量

sem是定义的信号量。pshared指定信号量是否进程共享,为0则线程共享,非0则进程共享。value则是计数器的初始值,表示想把公共资源分成多少份使用

2.申请信号量(P操作)

3.释放信号量(V操作)

4.销毁信号量

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

1.生产消费过程

生产者和消费者在环形队列的生产消费过程:

  1. 生产者不能把消费者套一个圈
  2. 消费者不能超过生产者
  3. 生产者和消费者只有两种场景会指向同一个位置:队列为空和为满

只要生产者和消费者不指向同一个位置,就可以多线程并发访问环形队列。如果为空,只能让生产者跑,如果为空,只能让消费者先跑。"只能"表现出的是互斥,"先"表现出的是同步。所以基于环形队列的生产者消费者模型,也有同步和互斥,但这种同步和互斥是局部性的,只有队列为空为满时才需要维持,这样就实现了生产和消费的并发。

2.信号量设计

生产者认为空间是资源,消费者认为数据是资源,所以分别为生产者和消费者设计条件变量,来表示空间和数据的数量。

初始时,生产者的信号量是n,消费者的信号量是0。
伪代码:

//1.初始化

p->sem_space = N;

c->sem_data = 0;

//2.生产者

P(sem_space)

//生产行为,位置待定

V(sem_data)

//3.消费者

P(sem_data)

//消费行为,位置待定

V(sem_space)

3.多生产和多消费

以上的两个信号量可以保证生产者和消费者之间的同步和互斥。如果是多个生产者和消费者,信号量能否保证生产者之间,消费者之间的互斥关系呢?

不能!因为生产者共用同一个_p_step,消费者共用同一个_c_step,读写位置的安全无法保证,也就不能保证多线程访问的是不同的位置,所以需要设计两个锁,分别对_p_step和_c_step进行保护。

相关推荐
IT_陈寒2 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
Sheffield3 小时前
Docker的跨主机服务与其对应的优缺点
linux·网络协议·docker
流浪克拉玛依3 小时前
Go Web 服务限流器实战:从原理到压测验证 --使用 Gin 框架 + Uber Ratelimit / 官方限流器,并通过 Vegeta 进行性能剖析
后端
孟沐3 小时前
保姆级教程:手写三层架构 vs MyBatis-Plus
后端
星浩AI3 小时前
让模型自己写 Skills——从素材到自动生成工作流
人工智能·后端·agent
华仔啊5 小时前
为啥不用 MP 的 saveOrUpdateBatch?MySQL 一条 SQL 批量增改才是最优解
java·后端
武子康6 小时前
大数据-242 离线数仓 - DataX 实战:MySQL 全量/增量导入 HDFS + Hive 分区(离线数仓 ODS
大数据·后端·apache hive
砍材农夫6 小时前
TCP和UDP区别
后端
千寻girling7 小时前
一份不可多得的 《 Django 》 零基础入门教程
后端·python·面试
千寻girling7 小时前
Python 是用来做 AI 人工智能 的 , 不适合开发 Web 网站 | 《Web框架》
人工智能·后端·算法