【Linux进程间通信(五)】System V 信号量

news2024/11/26 8:29:25

 (一)什么是信号量

互斥相关概念

1、并发:

2、互斥

3、临界资源&临界区

4、原子性

(二)信号量的理解

(三)信号量的两种基本操作 P / V

(四)信号量的内核数据结构

(五)信号量的相关接口

1、创建信号量 - semget 

2、释放信号量

(1)指令释放

(2)调用系统函数

3、PV操作 - semop


之前两个博客已经讲了System V IPC的两种形式:共享内存和消息队列,今天我们将System V IPC的最后一种方式 :信号量

(一)什么是信号量

System V 信号量是一种用于进程间通信和同步的机制,用于控制对共享资源的访问。它通常用于解决竞争条件和死锁等并发编程中的问题。

在正式学习信号量之前,我们需要先了解与互斥相关的四个概念,为后面多线程中信号量的学习作铺垫。

互斥相关概念

1、并发:
  • 并发是指在系统能够同时执行多个任务或者处理多个操作,这个概念在操作系统中非常重要,特别是在多用户系统和服务器环境中。
  • 并发主要在以下场景中应用:多任务处理、多线程、进程间通信、同步和互斥、并行处理以及事件驱动编程。
2、互斥
  • 互斥是一种资源访问控制的机制,用于确保在任意时刻只有一个进程或线程能够访问某个共享资源,以防止数据竞争和不一致性,可以避免竞态条件和死锁等并发编程中常见的问题。
  • 在并发编程中,互斥是确保共享资源在被一个进程或线程访问时处于被锁定状态,其他进程或线程需要等待锁释放后才能访问该资源的过程。
  • 在Linux中,实现互斥的常见方式包括使用互斥锁(mutex)和信号量。
3、临界资源&临界区
  • 临界资源指的是一种共享资源,它被多个线程或进程共同访问和修改。由于多个线程或进程可能同时尝试对该资源进行操作,因此需要采取措施来确保对该资源的访问是安全和有序的。
  • 临界区是指访问临界资源的代码段或区域。在临界区内,对临界资源的访问需要通过同步机制来保证其一致性。
  • 在并发程序中,为了保护临界资源,常常会使用互斥锁、信号量等同步机制来实现临界区的互斥访问。一旦一个线程或进程进入了临界区,其他线程或进程就不能进入,知道当前线程或进程离开临界区位置,这样可以避免数据竞争和不一致性。
4、原子性
  • 原子性是指一个操作是不可分割的或者是不可中断的。在并发编程中,原子性是指一个操作在执行过程中不会被其他线程的操作所干扰,要么该操作执行完成,要么没有执行,不会出现部分执行的情况。
  • 原子性通常用来描述对共享资源的访问或修改操作。如果一个操作是原子的,那么在多线程或多进程环境下,这个操作的执行过程中不会被其他线程或进程的操作所影响,可以确保数据的一致性和正确性。

(二)信号量的理解

将整个程序看作现实世界,人们看作执行流,电影院或手机等买票场所或方式看作临界区,而单场电影的电影票看作临界资源,电影院中单场电影余票的计数器就是信号量

当电影票卖完时,计数器归零,其他想看电影的人也无法购票观看本场电影

所以有了下面这些情况:

  1. 当你购票成功后,计数器-1,你必然可以去看这场电影,而其他人无法和你抢,因为那个位置已经是你的了。
  2. 如果你买票完了,票卖完了,计数器为0,你就无法购票观看这场电影,也就没有一个座位是属于你的。
  3. 因为有了计数器,电影院有效划分了电影票这个临界资源的所属权限,从而保证了在电影放映时,绝对不会发生位置冲突等各种情况。

信号量的设计就是为了避免 因为多执行流对临界资源的并发访问,而导致程序出现问题

互斥怎么理解呢?

我们可以想象一个VIP放映室,每次只允许一个进入看电影,和普通电影院一样,这个VIP放映室也有自己的计数器,但计数器初始值为1,这也叫二元信号量,而上面普通电影院的计数器则叫做计数信号量。

(三)信号量的两种基本操作 P / V

P操作(也成为down操作或者wait操作)

  • P操作用于获取(或者说获得)一个信号量,并且如果信号量的值大于0,就将它减一。如果信号量的值已经是0,那么P操作就会阻塞当前进程,直到信号量的值不再是0,然后再将其减一。
  • 在二元信号量中,P操作相当于将信号量的减一,并且在信号量的值变为0时会阻塞。

V操作(也成为up操作或者signal操作)

  • V操作用于释放(或者说放回)一个信号量,并将它的值加一。如果有其他线程因为等待信号量而阻塞,那么V操作就会唤醒其中一个被阻塞的进程。
  • 在二元信号量中,V操作相当于将信号量的值加一,并且在信号量的值从0变为1时会唤醒等待的进程。

这两种操作通常用于控制对共享资源的访问每一集实现线程或进程之间的同步。在许多操作系统和编程语言中,都提供了对信号量的支持,并且通常也提供了用于执行P和V操作的相应函数或者方法。

(四)信号量的内核数据结构

下面来看看信号量的数据结构,使用man semctl命令查看

           struct semid_ds {
               struct ipc_perm sem_perm;  /* Ownership and permissions */
               time_t          sem_otime; /* Last semop time */
               time_t          sem_ctime; /* Creation time/time of last
                                             modification via semctl() */
               unsigned long   sem_nsems; /* No. of semaphores in set */
           };
  • struct ipc_perm sem_perm:ipc_perm结构体类型,用于描述信号量的权限。
  • time _t sem_otime:表示信号量集上次操作的时间。
  • time_t sem_ctime :表示信号量集上次改变(包括创建、删除、修改)的时间。
  • unsigned long sem_nsems:表示信号量集中的信号量的数量。 

根据System V IPC的基本规律,struct ipc_perm中肯定存储了信号的权限,内容如下

           struct ipc_perm {
               key_t          __key; /* Key supplied to semget(2) */
               uid_t          uid;   /* Effective UID of owner */
               gid_t          gid;   /* Effective GID of owner */
               uid_t          cuid;  /* Effective UID of creator */
               gid_t          cgid;  /* Effective GID of creator */
               unsigned short mode;  /* Permissions */
               unsigned short __seq; /* Sequence number */
           };

由此我们可以总结出,无论是共享内存、消息队列、信号量,它们的ipc_perm结构体中的内容都是一摸一样的,结构上的统一可以带来管理上的便利,具体为什么是一样的可以接着往下看。 

(五)信号量的相关接口

1、创建信号量 - semget 

semget函数用于创建或者获取一个System V 信号量集的函数,其原型为:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

参数:

  • key_t key:用于唯一标识信号量集的键值,通常使用ftok函数来生成键值,也可以手动指定一个键值。
  • int nsems:标识需要创建或者获取的信号量数量。如果是创建操作,需要指定这个数量,如果是获取操作,该参数可以设为0。
  • int semflg:指定一些额外的标志位用于控制函数的行为。常见的标志包括IPC_CREAT和IPC_EXCL。

返回值 :

  • semget函数返回值为一个非负整数,标识信号量集的标识符(成为信号量集ID),如果出现错误,则返回-1,并设置错误码。

我们可以创建一个简单的例子,并用指令ipcs -s查看创建的信号量集的信息:

#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>

using namespace std;

int main()
{
	int n =semget(ftok("./",668),1,IPC_CREAT | IPC_EXCL | 0666);
	if(n == -1)
	{
		cerr<<"semget fail"<<endl;
		exit(1);
	}
	return 0;
}

2、释放信号量

(1)指令释放

我们可以用指令ipcrm -s semid直接释放信号量集

(2)调用系统函数

我们可以在代码中利用semctl函数来释放信号量集

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

参数:

  • semid:表示要操作的信号量集的标识符(即信号量集ID),由 semget() 函数返回。
  • semnum:表示要操作的具体信号量在信号量集中的索引,从0开始计数。
  • cmd:表示要执行的操作命令,可以是下列值之一:
    • GETVAL:获取指定信号量的当前值。
    • SETVAL:设置指定信号量的值。
    • GETPID:获取上次执行 semop() 操作的进程ID。
    • GETNCNT:获取当前正在等待资源的进程数。
    • GETZCNT:获取当前等待释放的资源的进程数。
    • GETALL:获取所有信号量的值。
    • SETALL:设置所有信号量的值。
    • IPC_RMID:从系统中删除信号量集。
  • 最后一个参数根据cmd参数的不同而有所变化。例如,对于SETVAL和GETVAL命令,需要传递一个union semun类型的参数,定义如下:
    union semun {
        int val;               // SETVAL 的参数,用于设置信号量的值
        struct semid_ds *buf;  // IPC_STAT 和 IPC_SET 的参数,用于获取或设置信号量集的信息
        unsigned short *array; // GETALL 和 SETALL 的参数,用于设置或获取所有信号量的值
        struct seminfo *__buf; // Linux 特有的参数,用于获取额外信息
    };
    

返回值:

  •  如果执行失败返回-1,并设置错误码;否则根据cmd参数的不同返回不同的值。

3、PV操作 - semop

semop函数使用于执行信号量操作的函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, size_t nsops);

 参数:

  • int semid:信号量集的标识符,由semget函数返回
  • struct sembuf *sops:一个指向sembuf结构体的制作真,每个sembuf结构描述一个信号量操作,定义如下:
    • struct sem_buf
      {
                 unsigned short sem_num;  /* semaphore number */
                 short          sem_op;   /* semaphore operation */
                 short          sem_flg;  /* operation flags */
      };

      其中sem_num代表信号量在集合中的索引;sem_op表示要进行的操作,负数表示P操作,正数表示V操作,0表示检查信号量值;sem_flg 操作标志,可以为IPC_NOWAIT或者SEM_UNDO。

返回值:

  • 操作成功返回0,否则返回-1,并设置错误码。

这就是System V 信号量部分的内容了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1652238.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

列表、字典推导式介绍和用法|lambda的介绍和用法

列表、字典推导式介绍和用法|lambda的介绍和用法 列表推导式示例应用与传统写法代码行数直观比较 字典推导式示例应用 lambda示例应用 列表推导式、字典推导式、lambda使用简洁语法进行代码的编写 列表推导式 用于快速创建新的列表&#xff0c;通过对现有列表进行迭代和筛选。…

pytest(二):关于pytest自动化脚本编写中,初始化方式setup_class与fixture的对比

一、自动化脚本实例对比 下面是一条用例,使用pytest框架,放在一个类中,两种实现方式: 1.1 setup_class初始化方式 1. 优点: 代码结构清晰,setup_class 和 teardown_class 看起来像传统的类级别的 setup 和 teardown 方法。2. 缺点: 使用 autouse=True 的 fixture 作为…

文件夹名称大小写转换:名称首字母转大写,一种高效的文件管理方法

在日常生活和工作中&#xff0c;电脑文件夹的管理对于提高工作效率和文件检索的便捷性至关重要。文件夹名称的命名规则直接影响到文件组织的有序性和查找的速度。其中&#xff0c;将文件夹名称的首字母转换为大写是一种简单而高效的管理方法&#xff0c;下面我们就来详细探讨实…

Spring Security 入门1

1. 概述 基本上&#xff0c;在所有的开发的系统中&#xff0c;都必须做认证(authentication)和授权(authorization)&#xff0c;以保证系统的安全性。 authentication [ɔ,θɛntɪ’keʃən] 认证 authorization [,ɔθərɪ’zeʃən] 授权 以论坛举例子&#xff1a; 【认证…

Context capture/Pix4Dmapper/AutoCAD/CASS/EPS软件的安装流程与使用方法;土方量计算;无人机摄影测量数据处理

目录 专题一 无人机摄影测量技术应用现状及其发展 专题二 基本原理和关键技术讲解 专题三 无人机影像外业数据获取 专题四 数据处理环境建立与软件熟悉 专题五 GNSS数据土方量计算 专题六 基于无人机影像数据的正射影像制作 专题七 基于无人机影像数据的三维模型制作 专…

号称能打败MLP的KAN到底行不行?数学核心原理全面解析

前几天火爆的Kolmogorov-Arnold Networks是具有开创性&#xff0c;目前整个人工智能社区都只关注一件事LLM。我们很少看到有挑战人工智能基本原理的论文了&#xff0c;但这篇论文给了我们新的方向。 mlp或多层感知位于AI架构的最底部&#xff0c;几乎是每个深度学习架构的一部…

为什么 ChatGPT 不火了?

不火了是有原因的&#xff0c;下面我来从大部分人拿到 ChatGPT 之后的两大痛点开始讲起&#xff1a; 很多朋友拿到 ChatGPT 后的第一个痛点就是&#xff1a;用的不好 你经常会感觉到 ChatGPT 回答的好空&#xff0c;没有太多参考价值。 而第二个痛点则是&#xff1a;无处去用…

【Gateway】网关集成Knife4j—swagger接口文档

文章目录 前言一、相关配置1.网关gateway配置①.网关增加配置 pom文件②.网关增加配置 SwaggerHandler③.网关增加配置 SwaggerResourceConfig④.网关增加配置 SwaggerConfig 2.网关过滤器 二、接口文档使用1.访问文档2.查看文档 总结 前言 在日常开发中是需要前后端联调的&am…

加密杂谈:Base 向上,BSC 向下

Aerdrome 价格走过一轮&#xff0c;Base 一己之力扶持起巅峰 1B Mcap, 2B FDV 的百倍币&#xff0c;秀出了肌肉&#xff0c;其所带来的正外部性也进一步盘活了 Base 生态 反观 BSC 本轮哪怕靴子落地依然没个响&#xff0c;差距在哪里&#xff1f;本 Thread 将以此为切入点探讨…

Vue3:menu导航栏出现多个同一跳转路径的菜单处理

文章目录 需求整理实现思路实现过程 需求整理&#xff0c;实现思路 最近公司想将之前老的项目整理出来&#xff0c;因为这个老项目内容太杂什么页面都往里面塞&#xff0c;导致菜单特别多&#xff0c;公司就像将这个老的项目迁出来&#xff0c;这个旧的项目本来是后端PHP写的。…

【保姆级详细步骤教学用DOSBoxV0.74写出一个汇编语言程序输出Hello World!】

使用任何文本编辑器创建一个名为 HELLO.ASM 的文件&#xff0c;并将以下代码粘贴到文件中&#xff1a; .MODEL SMALL .STACK 100H.DATAMSG DB Hello, World!, $PROMPT DB 13, 10, Press any key to exit..., $.CODEMAIN PROCMOV AX, DATAMOV DS, AXMOV AH, 09HLEA DX, MSGINT …

用户页面触发点击事件和 js 执行点击事件的区别

文章目录 情景展示情况一&#xff1a;用户点击页面触发情况二&#xff1a;通过 js 触发点击 结果分析情况一情况二 其实这个谜底揭开之后&#xff0c;第一反应都是&#xff0c;哦~&#xff0c;非常简单&#xff0c;但是细节决定成败&#xff0c;我被这个细节毁掉了&#xff0c;…

docker资源限额

多数的应⽤场景要对Docker容器的运⾏内存进⾏限制&#xff0c;防⽌其使⽤过多的内存。 格式&#xff1a;-m或--memory 正常的内存大小 [rootadmin ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

硬件设计——滤波器设计_MIC用有源带通滤波器

“在已有的成熟稳定的滤波器基础上&#xff0c;根据业务需要对原设计进行优化调整以得到新的滤波器” 是滤波器设计的一种常用方法。 MIC用有源带通滤波器 介绍一种简单直观的带通滤波器以及计算过程&#xff0c;以作未来可参考的基线设计。该滤波器可用于音频信号&#xff0…

【算法】基础算法004之前缀和

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 本篇文章为大家带来前缀和…

【EI会议|投稿优惠】2024年物理化学与应用数学国际会议(IACPCAM 2024)

2024 International Conference on Physical Chemistry and Applied Mathematics 一、大会信息 会议名称&#xff1a;2024年物理化学与应用数学国际会议会议简称&#xff1a;IACPCAM 2024收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等会议官网&#xff1a;…

基于树莓派的六足机器人方案设计+源代码+工程内容说明

文章目录 源代码下载地址项目介绍项目内容说明简单预览 项目备注源代码下载地址 源代码下载地址 点击这里下载源码 项目介绍 项目内容说明 hardware为项目相关硬件设计 机械结构为六足机器人的3d建模工程&#xff0c;包括本体和云台遥控器在ESP32最小开发板上集成了MPU605…

Python面向对象编程思想的深入学习

魔术方法的使用 案例体验 class Student:def __init__(self, name, age):self.name nameself.age age# __str__魔术方法, 如果不去写这个方法&#xff0c;那么print输出的则是信息存储的内存地址。def __str__(self):return fStudent类对象&#xff0c;name:{self.name}, ag…

入门视频剪辑:视频合并不再难,批量嵌套合并的简单步骤

在数字媒体时代&#xff0c;视频剪辑已成为一项基本技能。无论是制作家庭电影、公司宣传片还是在线教育内容&#xff0c;视频剪辑都扮演着重要角色。对于初学者来说&#xff0c;视频剪辑可能看起来有些复杂&#xff0c;但掌握了正确的步骤和技巧后&#xff0c;你会发现它其实并…

【资源分享】PyCharm2020安装教程

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…