Linux进程通信——信号量

news2024/11/29 21:43:27

概念

信号量(semaphore) 与已经介绍过的 PC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

特点

1.信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
2.信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作

PV操作一种实现进程互斥与同步的有效方法。PV操作与信号量的处理相关,P表示通过的意思,V表示释放的意思
原子操作指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch(切换到另一个线程)

3.每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数
4.支持信号量组

使用原理

最简单的信号量是只能取 0和 1的变量,这也是信号量最常见的一种形式,叫做二值信号量 Binary Semaphore) 。而可以取多个正整数的信号量被称为通用信号量

Linux 下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。

semget函数

创建或获取一个信号量组:若成功返回信号量标识符ID,失败返回-1。

函数原型

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

参数解读

key所创建或打开信号量集的键值
nsems信号量的个数,通常为1;如果是引用一个现有的集合,则将nsems指定为 0,该参数只在创建信号量集时有效
semflg调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过 | 表示

semctl函数

控制信号量的相关信息。

函数原型

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

参数解读

semidsemget函数返回的信号量标识符ID
semnum操作信号在信号集中的编号,这里是以数组为单位的,所以第一个单位是数组中的第一个,即为0
cmd对信号量进行相关操作

在semctl函数中的cmd有多种,这里就说两个常用的:

SETVAL用于初始化信号量为一个已知的值。所需要的值作为联合体semun的val成员来传递,在信号量第一次使用之前需要设置信号量
IPC_RMID删除一个信号量集合。如果不删除信号量,它将继续在系统中存在,即使程序已经退出,它可能在你下次运行此程序时引发问题,而且信号量是一种有限的资源

如果有第四个参数,它通常是联合体union semun,定义格式如下:

union semun
{
	int val;    /* Value for SETVAL */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

semop函数

对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1。

函数原型

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

参数解读

semidsemget函数返回的信号量标识符ID
*sops通常是一个结构体数组,但信号量理论上一次只能执行一个,所以在定义该结构体时,不需要以数组格式定义
nsops信号操作结构的数量,恒大于或等于1

*sops结构体定义格式如下:

struct sembuf
{
    short sem_num; // 信号量的编号,默认为0
    short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
                   // 一个是+1,即V(发送信号)操作。
    short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,当进程结束之前,取消对信号量的任何操作
};

代码示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//模拟用钥匙开锁场景

union semun//定义一个联合体
{
	    int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO*/
};

void pGetKey(int semid)
{
	struct sembuf set;//定义一个结构体
	set.sem_num = 0;//第一个信号量
	set.sem_op = -1;//拿走钥匙 数量-1
	set.sem_flg = SEM_UNDO;//拿不到钥匙就等待
	semop(semid,&set,1);//第二个参数为指针,这里需要以地址形式写入
	printf("get the key\n");
}

void vPutBackKey(int semid)
{
        struct sembuf put;
        put.sem_num = 0;
        put.sem_op = +1;//放回钥匙 数量+1
        put.sem_flg = SEM_UNDO;
        semop(semid,&put,1);
	printf("put back the key\n");
}

int main()
{
	int semid;
	int pid;

	key_t key;
	key = ftok(".",1);

	semid = semget(key,1,IPC_CREAT|0666);//以可读可写权限创建信号量
	
	union semun initsem;//调用联合体:初识化钥匙数量
    initsem.val = 0;//一开始钥匙数量为0

	semctl(semid,0,SETVAL,initsem);
	
	pid = fork();
	if(pid > 0)
	{
		pGetKey(semid);//拿钥匙 但钥匙数量为0 需等待钥匙放回 即等待子进程放回钥匙
		printf("this is father\n");
		vPutBackKey(semid);//拿到钥匙后使用完毕放回钥匙
	}
	else if(pid == 0)
	{
		printf("this is child\n");
		vPutBackKey(semid);//将钥匙放回,钥匙数量+1,父进程检测到有钥匙就拿钥匙,即先进入子进程再进入父进程
	}
	else
		printf("error!\n");
	
	return 0;
}



可见,一开始没有钥匙,父进程中没有任何操作,当子进程中将钥匙放回时,父进程检测到后拿到钥匙使用完毕后并放回。实现信号量的检测。

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

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

相关文章

C语言线性表的链式存储(框架)

线性表的链式存储 线性表的顺序存储&#xff1a;用一块连续的内存空间 线性表的链式存储&#xff1a;不连续的内存空间 链表是由一系列的节点组成&#xff0c;每个节点包含两个域&#xff0c;一个是数据域&#xff0c;一个是指针域 链表的插入和删除原理 单项链表框架的搭建 …

交换机配置与管理

文档以国产迈普交换机为例&#xff0c;各厂家交换机配置有少许不同&#xff0c;仅供参考。 交换机命令行模式&#xff1a; 普通用户模式Hostname>&#xff08;&#xff09; exit 输入enable命令 特权用户模式Hostname#&#xff08;&#xff09; exit 输入configu…

业务流程图是什么,怎么画?

业务流程图是一种展示企业内部流程和工作流程的图表&#xff0c;通常以图表的形式呈现。业务流程图用图像化的方式展示组织内部的各种活动&#xff0c;每个操作环节被展示为流程图的一个框&#xff0c;一般包括输入/输出、任务和活动等元素。 业务流程图的使用场景 业务流程…

深入理解JVM虚拟机第二十六篇:详解JVM当中的虚方法和非虚方法,并从字节码指令的角度去分析虚方法和非虚方法

😉😉 学习交流群: ✅✅1:这是孙哥suns和树哥给大家的福利! ✨✨2:我们免费分享Netty、Dubbo、k8s、Spring...应用和源码级别的视频资料 🥭🥭3:QQ群:583783824 📚​​​​​​​📚 微信:DashuDeveloper拉你进微信群,免费领取! 一:非虚方法和虚方法 方法…

OpenGL的学习之路 -5

1.视景体 正交投影 人眼看世界&#xff0c;有一个可见范围。范围内可见&#xff0c;范围外不可见。视景体就是这么一个概念。 &#xff08;上图仅学习记录用&#xff09; 在OGL中&#xff0c;有两种投影方式&#xff0c;对应两种视景体。第一种&#xff0c;正交投影&#xf…

声音响度、声压级计权(A B C)实现

声压 sound pressure 声压就是大气压受到声波扰动后产生的变化&#xff0c;即为大气压强的余压&#xff0c;它相当于在大气压强上的叠加一个声波扰动引起的压强变化。由于声压的测量比较容易实现&#xff0c;通过声压的测量也可以间接求得质点速度等其它物理量&#xff0c;所以…

人工智能入门教学——AI代理(AI Agent)

目录 一、简介 二、特征 三、结构 四、工作流程 五、类型 六、应用 一、简介 AI代理 (Artificial Intelligence Agent)是指使用人工智能技术和算法来执行特定任务、解决问题或实现目标的程序或系统。这些代理可以是简单的程序&#xff0c;也可以是复杂的系统&#xff0c…

学生党福音!一个能自定义词库的单词软件--单词魔方

大家好 我是Yhen 这一期给大家介绍一款自制的单词软件–单词魔方 文章目录 一.创作缘由二.功能介绍&升级内容三.使用方法四.程序获取 一.创作缘由 为什么会有想法开发这个单词软件呢&#xff1f; 因为平时自己在做阅读&#xff0c;看电影时积累下来了一些单词 当我想要系…

Spring Cache(缓存框架)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

C++ libcxxabi中dynamic_cast 实现

摘要&#xff1a;最近在看一个崩溃的过程中详细看了一遍cxxabi的定义&#xff0c;就想着看一些llvm中cxxabi的一些实现。本文描述了cxxabi中dynamic_cast的实现以及原理。   关键字&#xff1a;cxxabi,dynamic_cast 1 简介 C中&#xff0c;dynamic_cast用于有虚函数的继承链…

Linux系统管理:WinSCP 安装与使用

目录 一、实验 1.下载WinSCP 2.安装WinSCP 3.使用WinSCP 一、实验 1.下载WinSCP &#xff08;1&#xff09;地址 Downloading WinSCP-6.1.2-Setup.exe :: WinSCP 2.安装WinSCP &#xff08;1&#xff09;选择安装程序模式 &#xff08;2&#xff09;点击 &#xff08;3…

vite-性能优化-构建优化-cnd加速优化

CDN 加速优化 - 感觉用不大到 主要作用 &#xff1a; 将引入的依赖&#xff0c;打包部署后&#xff0c;在用户访问的时候&#xff0c; 通过网络CDN的方式进行加载&#xff0c;而非直接从你自己的服务器上加载。优点 &#xff1a; 1、直接降低了你自己的打包的体积&#xff0c…

基于helm的方式在k8s集群中部署gitlab - 部署(一)

文章目录 1. 背景说明2. 你可以学到什么&#xff1f;3. 前置条件4. 安装docker服务&#xff08;所有节点&#xff09;5. 部署k8s集群5.1 系统配置&#xff08;所有节点&#xff09;5.2 安装kubelet组件(所有节点)5.2.1 编写kubelet源5.2.2 安装kubelet5.2.3 启动kubelet 5.3 集…

2023nacos源码解读第4集——整体了解nacos源码模块

文章目录 1、类Linux tree的windows treee工具2、源码目录结构3、模块依赖关系 1、类Linux tree的windows treee工具 windows 自带的tree 不够用&#xff0c;使用node npm安装一个类Linux 的treee npm install -g cnpm --registryhttps://registry.npm.taobao.org npm config…

MySQL 8 手动安装后无法启动的问题解决

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;…

springframe工程导入

配置gradle工程 init.d 目录下新建init.gradle allprojects {repositories {mavenLocal()maven {allowInsecureProtocol trueurl https://maven.aliyun.com/nexus/content/repositories/central/}} } 报错Plugin [id: org.jetbrains.dokka, version: 0.10.1, apply: false] w…

Python集合类型

目录 目标 版本 官方文档 集合分类 实战 创建 循环 常用方法 目标 掌握set和frozenset两种集合的使用方法&#xff0c;包括&#xff1a;创建、交集、并集、差集等操作。 版本 Python 3.12.0 官方文档 Set Types — set, frozensethttps://docs.python.org/3/library/s…

常见指令的数据通路和执行过程

作此篇的原因是17年19题&#xff1a; 本题选A&#xff0c;做的时候总感觉不够通透&#xff0c;因此把这题涉及到的内容全部看了一遍&#xff0c;顿时没有那种朦胧感了 零、五段式流水线&#xff1a; 以下均为MIPS设定&#xff1a;指令长度为32位&#xff0c;主存按字节编址&a…

RC-MVSNet:无监督的多视角立体视觉与神经渲染--论文笔记(2022年)

RC-MVSNet&#xff1a;无监督的多视角立体视觉与神经渲染--论文笔记&#xff08;2022年&#xff09; 摘要1 引言2 相关工作2.1 基于监督的MVS2.2 无监督和自监督MVS2.3 多视图神经渲染 3 实现方法3.1 无监督的MVS网络 Chang, D. et al. (2022). RC-MVSNet: Unsupervised Multi-…

领域驱动设计总结——如何构造领域模型

领域驱动设计总结——如何构造领域模型 本文为领域驱动设计系列总结的第三篇&#xff0c;主要对领域驱动设计概念做个介绍&#xff0c;本系列领域驱动设计总结主要是在Eric Evans 所编写的《领域驱动设计》 一书的基础上进行归纳和总结。本文主要介绍在领域驱动设计中如何构造…