当前位置: 首页 > news >正文

进程间通信--信号量【Linux操作系统】

文章目录

  • 并发编程相关基础概念
  • 信号量
    • 深刻理解信号量
      • 使用共享资源的方式
      • 分块使用共享资源的方式会出现的问题
      • 举例子理解信号量的第二个特性---预定
      • 信号量要成为计数器面临的问题
    • 信号量相关操作接口--POSIX
      • 库函数:sem_init
      • 库函数:sem_destroy
      • 库函数:sem_wait
      • 库函数:sem_post
    • 信号量相关操作接口--systemV
      • 系统调用:semget
      • 系统调用:semop

并发编程相关基础概念

在这里插入图片描述

保护共享内存的本质就是:
对访问共享内存的代码(临界区)进行限制

信号量

信号量和其他进程间通信的作用不太一样,它主要是用来实现进程(线程)间同步互斥的

信号量(进程)的生命周期也和共享内存一样:随内核
所以
①要么由进程使用系统调用释放信号量
②要么操作系统重启



深刻理解信号量

信号量本质是一个对资源进行预定的计数器



使用共享资源的方式

访问临界资源的时候,有两种访问方式:

  • 1.一次直接使用一整个临界资源
    比如
    我们之前对管道的使用,从来就没有考虑过写入位置和读取位置在哪的问题
    只是直接从管道读取,直接向管道写入,是直接以一整个管道为单位进行使用

    • 此时出于对共享资源的保护的互斥性,一次就只能一个进程访问这个管道
  • 2.把一个临界资源分成多个分区,让不同进程可以使用不同分区
    这样的好处是:

    • 1.可以在不违反保护共享资源特性的情况下,一个共享资源可以被多个进程同时使用(并发使用)
    • 2.申请一块共享资源非常繁琐,所以如果多个进程想两两通信
      可以只申请一块共享资源,再把它分区给所有进程使用
    • 只申请一块共享资源也可以减少使用系统调用


分块使用共享资源的方式会出现的问题

分块使用共享资源虽然可以做到一块共享资源,多个进程并发使用
但是一种方法了解决一个问题,必然又会出现新的问题
这个新的问题就是:
共享资源的分区个数<进程个数怎么办?

例如
我们把一个共享资源分成了16个区,但是同时来了30个进程要访问共享资源怎么办?
在这里插入图片描述

此时再怎么分配,也不可能让所有进程同时使用这个共享资源=
只能先分配16个进程,等一些进程使用丸了,再让剩下的进程进来用
如何做到这一点呢?
使用计数器!!!

  1. 让计数器等于分区数,这样一个进程要使用共享资源前,都先判断一下const是否>0
    如果是就是还有分区空着,可以给它,再count--
    如果不是,就让进程阻塞等待

  2. 同理,如果有一个进程退出了临界区,就会有一个分区空出来,count++

所以本质上共享资源使用方法1和2其实是一样的,因为整体使用时不就是分区个数只有1个吗?



举例子理解信号量的第二个特性—预定

我们生活中,不管是看电影还是坐高铁,都要买票,因为它们的名额都是需要竞争的资源
买票的本质就是:对资源进行预定
就是买到票了,我就算不去,那个资源也是属于我的

而且票的个数也有限,因为资源的个数有限,不能出现两个人用同一个资源的情况,所以票又何尝不是一个计数器呢?

我们上面所说的进程竞争使用共享资源的分区,本质也是如此
只要一个进程抢到了计数器的名额,共享资源中就一定有一个分区会给它

所以信号量的本质是和票一样,是对资源进行预定的计数器

所以
人们抢高铁座位,其实是抢票
进程抢共享资源的分区,其实是抢计数器(信号量)名额

所以共享资源分区,最重要的不是分配,而是对计数器(信号量)的正确使用

对共享资源整体使用的时候,计数器count不是等于0就是等于1
此时称这个计数器为:二元信号量或者锁



信号量要成为计数器面临的问题

  • 1.如何让不同进程看到计数器(信号量)呢?
    让信号量作为共享资源!!!

  • 2.信号量本身就是共享资源,它去包含其他的共享资源,那谁来保护它呢?
    比如两个进程同时看见信号量还剩一个,它们同时去抢,同时抢到手,count同时=0
    这不就卡bug了吗?

信号量本质是一个对共享资源进行预定的计数器
计数器的操作无非就是++和–
只要让这两个操作都具有不可中断的原子性不就可以了吗?
所以操作系统为信号量专门定义了具有两个原子性的操作
即P操作[++]和V操作[–]



信号量相关操作接口–POSIX

使用信号量接口之前,需要定义一个信号量对象(sem_t类型)

库函数:sem_init

  • 头文件:semaphore.h

  • 参数表:

    • 1.sem_t*sem
      要初始化的信号量的地址

    • 2.int pshared
      1.如果是pshared是0,则表示线程间信号量
      2.如果是pshared非0,则表示进程间信号量

    • 3.unsigned int val
      即:信号量这个计数器的初始值,也就是把共享资源分成几份/共享资源的个数

  • 作用:
    初始化对应的信号量


库函数:sem_destroy

  • 头文件:semaphore.h

  • 参数表:
    sem_t*sem:要销毁的信号量的地址

  • 作用:
    销毁对应的信号量


库函数:sem_wait

  • 头文件:semaphore.h

  • 参数表:
    sem_t*sem:对应的信号量的地址

  • 作用:
    申请信号量,P操作,信号量–
    (申请信号量失败【即信号量减到0】,线程/进程会被阻塞)


库函数:sem_post

  • 头文件:semaphore.h

  • 参数表:
    sem_t*sem:对应的信号量的地址

  • 作用:
    释放信号量,V操作,信号量++



信号量相关操作接口–systemV

如果有多个共享内存要分区使用,那么就需要多个信号量

所以操作系统提供信号量,是以信号量集合的方式提供的
即:申请信号量的时候,申请的是一个/多个信号量


系统调用:semget

  • 头文件:
    sys/types.hsys/ipc.hsys/sem.h

  • 返回值:int类型
    ①成功,返回用户(进程)使用的信号量集合标识符合条件
    ②失败,返回-1

  • 参数表:

    • key_t key:内核中唯一标识一个信号量集合(key的获取和使用方法于共享内存的key一模一样,使用ftok获取

    • int nsems:信号量集合中的信号量个数

    • int semflag:位图标志位
      也和共享内存的一模一样
      IPC_CREAT:单独使用的话如果对应的共享内存不存在,就创建。存在就返回shmid
      该选项主要给获取共享内存的进程使用
      IPC_EXCL:不能单独使用
      但是
      IPC_CREAT | IPC_EXCL
      如果对应的共享内存不存在,就创建并在页表建立映射关系
      存在就报错
      该选项主要给创建共享内存的进程使用

  • 作用:创建(获取)一个信号量集合


系统调用:semop

  • 头文件:
    sys/types.hsys/ipc.hsys/sem.h

  • 参数表:

    • int semid:进程使用的信号量集合唯一标识

    • struct sembuf*p:指向一个struct sembuf的数组的起始地址
      struct sembuf
      {
      int sem_num//信号量集合的下标
      short sem_op//-1表示–,1表示++
      short sem_flaf//一般不管,设置为0
      }
      semop这样设计是为了,可以同时对一个信号量集合中的多个信号量进行PV操作或者对信号量集合进行整体操作

    • ③int nsops :参数②指向的数组的元素个数

  • 作用:对一个信号量集合中的一个/多个信号量进行PV操作

http://www.xdnf.cn/news/520201.html

相关文章:

  • leetcode解题思路分析(一百六十四)1418 - 1424 题
  • [论文品鉴] DeepSeek V3 最新论文 之 MHA、MQA、GQA、MLA
  • 进程状态并详解S和D状态
  • C++学习:六个月从基础到就业——C++17:结构化绑定
  • 什么是dom?作用是什么
  • 产品周围的几面墙
  • C++高级用法--绑定器和函数对象
  • 垂直智能体:企业AI落地的正确打开方式
  • [人月神话_6] 另外一面 | 一页流程图 | 没有银弹
  • 三:操作系统线程管理之用户级线程与内核级线程
  • 大模型应用开发工程师
  • 从逻辑学视角探析证据学的理论框架与应用体系;《证据学》大纲参考
  • Java学习手册:服务熔断与降级
  • 朴素贝叶斯
  • 做什么, what to do?
  • 面试题总结二
  • atcoder C - ~
  • EmuEdit
  • 网页 H5 微应用接入钉钉自动登录
  • python29
  • 【从基础到模型网络】深度学习-语义分割-ROI
  • C++ - 网络编程之初始连接(Winsock2 概述、初始连接案例、初始连接案例解读)
  • 封装、继承、多态的理解
  • Java面试实战:从Spring Boot到分布式缓存的深度探索
  • 程序代码篇---python获取http界面上按钮或者数据输入
  • 批量下载AlphaFold结构
  • leetcode刷题日记——翻转二叉树
  • 第11章 JDBC与MySQL数据库
  • UI架构的历史与基础入门
  • GOP模式调节画面质量讲解