linux应用 进程间通信之信号量(System V)

1、定义

System V 信号量是一种用于进程间同步和互斥的机制,它是 System V IPC(Inter-Process Communication,进程间通信)机制的一部分。信号量通常用于控制对共享资源的访问,以避免竞争条件(race condition)和数据不一致性。

一般来说,System V 信号量常用于以下场景:

  • 进程同步:多个进程需要协调执行顺序,例如在生产者-消费者问题中,生产者和消费者需要同步对共享缓冲区的访问。
  • 资源互斥:多个进程需要互斥地访问共享资源,例如文件、打印机、设备等。
  • 进程间通信:信号量也可以用于进程间的通信,通过信号量的值来进行信息传递。:

优点:

  • 高效性:信号量是一种轻量级的同步机制,适用于对共享资源的快速访问和控制。
  • 多种同步操作:信号量支持多种同步操作,包括 P(等待)操作和 V(释放)操作,可以灵活地控制对资源的访问。
  • 可扩展性:信号量可以用于控制多个资源的访问,适用于复杂的同步和互斥场景。

缺点:

  • 复杂性:与其他进程间通信机制相比,信号量的使用可能更为复杂,容易出现死锁等问题。

重要概念:

  • P 操作:P 操作用于请求进入临界区(临界区是一段代码,一次只允许一个进程进入执行)。如果信号量的值大于 0,那么执行 P 操作会将信号量的值减 1,并允许进程进入临界区执行。如果信号量的值已经为 0,那么执行 P 操作的进程会被阻塞,直到信号量的值变为非零为止。
  • V 操作:V 操作用于离开临界区。执行 V 操作会将信号量的值加 1。如果有其他进程因为执行 P 操作而被阻塞,那么执行 V 操作会唤醒其中一个被阻塞的进程。

2、常用接口介绍

2.1 编程常用接口和数据结构

2.1.1 ftok函数

ftok函数用于生成一个System V IPC对象(如消息队列、共享内存等)的key。它将pathname和proj_id组合起来,生成一个唯一的key,用于标识一个System V IPC对象。

key_t ftok(const char *pathname, int proj_id);
  • 入参:pathname是一个路径名,proj_id是一个用户指定的整数。
  • 返回值:返回一个基于pathname和proj_id生成的key。
2.1.2 semget函数

semget 用于创建一个新的信号量集或者获取一个已存在的信号量集。

int semget(key_t key, int nsems, int semflg);
  • 入参:key用于标识信号量集的键值,通常使用 ftok 函数生成,nsems信号量集中包含的信号量数量,semflg:用于指定信号量的权限和标志,通常使用 IPC_CREAT 来创建一个新的信号量集。
  • 返回值:返回一个信号量集的标识符(semid)。
2.1.3 semctl函数

semctl 用于对信号量集进行控制操作,比如初始化、获取值、设置值、删除等。

int semctl(int semid, int semnum, int cmd, ...);
  • 入参:semid信号量集的标识符,semnum信号量的索引,通常为 0,cmd:控制命令,用于指定要进行的操作,比如 SETVAL 用于设置信号量的值,... 根据不同的命令,可能会有额外的参数。
  • 返回值:根据不同的命令,返回不同的值。

cmd取值如下:

  • GETVAL:获取信号量的值
  • SETVAL:设置信号量的值
  • GETPID:获取上次执行 semop 操作的进程ID
  • GETNCNT:获取当前等待信号量值增加的进程数
  • GETZCNT:获取当前等待信号量值减少的进程数
  • GETALL:获取所有信号量的值
  • SETALL:设置所有信号量的值
  • IPC_RMID:删除信号量

当第三个参数为 SETVAL 时,需要第四个参数,第四个参数是一个 union semun 结构体类型的变量,用于指定要设置的信号量的值。

当第三个参数为 SETALL 时,需要第四个参数,第四个参数是一个指向 short 类型数组的指针,数组的长度等于信号量集中的信号量数量,用于指定要设置的所有信号量的值。

2.1.4 semop函数

semop 用于执行对信号量的操作,比如等待(P操作)和释放(V操作)。

int semop(int semid, struct sembuf *sops, unsigned nsops);
  • 入参:semid信号量集的标识符,sops指向一个 sembuf 结构体数组的指针,每个 sembuf 结构体描述了一个操作,nsops:sops 数组中结构体的数量。
  • 返回值:成功返回 0,失败返回 -1。
2.1.5 struct sembuf
struct sembuf {unsigned short sem_num;  // 信号量在信号量集中的索引short sem_op;             // 操作值,可以是正数(V操作)或负数(P操作)short sem_flg;            // 操作标志位,可以使用 IPC_NOWAIT 等标志
};
sem_op sem_flg 结果影响
正数执行 V(释放)操作,增加信号量的值。如果信号量的值非负,就会唤醒等待该信号量的进程。操作成功返回,否则返回失败。
负数执行 P(等待)操作,减少信号量的值。如果信号量的值小于 0,就会阻塞等待直到信号量的值变为非负。操作成功返回,否则返回失败。
0执行 Z(等待直到值为 0)操作,等待信号量的值变为 0。如果信号量的值不为 0,就会阻塞等待。操作成功返回,否则返回失败。
任意IPC_NOWAIT如果操作无法立即进行,就会立即返回,而不是阻塞等待。如果操作成功返回,否则返回失败。
任意SEM_UNDO系统会跟踪对信号量的修改,并在进程终止时撤销这些修改,以防止进程异常终止导致信号量的值不一致。如果操作成功返回,否则返回失败。
2.1.6 union semun
union semun {int val;              // 用于设置单个信号量的值struct semid_ds *buf; // 用于获取或设置信号量集的属性unsigned short *array; // 用于设置所有信号量的值
} arg;struct semid_ds {struct ipc_perm sem_perm; // 信号量集的权限信息time_t sem_otime; // 上次操作时间time_t sem_ctime; // 上次修改时间unsigned short sem_nsems; // 信号量集中的信号量数量
};struct ipc_perm {key_t key; // IPC 对象的键值uid_t uid; // 所有者的用户IDgid_t gid; // 所有者的组IDuid_t cuid; // 创建者的用户IDgid_t cgid; // 创建者的组IDmode_t mode; // 权限
};

2.2 控制台常用命令

2.2.1 ipcs

ipcs命令用于显示系统中的IPC资源信息,包括消息队列、共享内存和信号量。-s选项表示只显示信号量的信息:

ipcs -s
2.2.2 ipcrm

ipcrm命令用于删除指定的 IPC 对象,包括信号量:

ipcrm -s <semid>

3、编程示例

测试代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include <sys/msg.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>#define SEM_FILE_PATH "/home/sem"
#define INIT_NUM 2// 打印时分秒的宏        
#define PRINT_MIN_SEC() do { \time_t t = time(NULL); \struct tm *tm_ptr = localtime(&t); \printf("%02d:%02d:%02d:", tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec); \} while (0)int main(int argc, char *argv[]) 
{key_t key;int semid;struct sembuf sops = {0};// 文件不存在则创建文件if (-1 == access(SEM_FILE_PATH, F_OK)){system("touch "SEM_FILE_PATH);}// 获取keyif((key = ftok(SEM_FILE_PATH, 'a')) < 0){return 0;}// 创建一个信号量集semid = semget(key, 1, IPC_CREAT | 0666); // 命令行参数 // 第一个参数      P表示P操作 V表示V操作 I表示设置初始值为INIT_NUM D表示删除if (argc != 2) {printf("Usage: %s P|V|I|D", argv[0]);return 0;}if (!strcmp(argv[1], "P")){PRINT_MIN_SEC();printf("*****P Opt*****\n");sops.sem_num = 0;sops.sem_op = -1; // P 操作sops.sem_num = 0;semop(semid, &sops, 1); // 执行 P 操作PRINT_MIN_SEC();printf("!!!Inter P Zero!!!\n");} else if (!strcmp(argv[1], "V")) {PRINT_MIN_SEC();printf("*****V Opt*****\n");sops.sem_num = 0;sops.sem_op = 1; // V 操作sops.sem_num = 0;semop(semid, &sops, 1); // 执行 V 操作} else if (!strcmp(argv[1], "I")) {PRINT_MIN_SEC();printf("*****Init Opt*****\n");// 设置信号量的值union semun {int val;struct semid_ds *buf;unsigned short *array;} arg;arg.val = INIT_NUM;semctl(semid, 0, SETVAL, arg);} else if (!strcmp(argv[1], "D")) {PRINT_MIN_SEC();printf("*****Delete Opt*****\n");semctl(semid, 0, IPC_RMID);} else{printf("Usage: %s P|V|I|D", argv[0]);return 0;}// 执行完操作后打印状态struct semid_ds seminfo;semctl(semid, 0, IPC_STAT, &seminfo);PRINT_MIN_SEC();printf("SME Value: %d\n", semctl(semid, 0, GETVAL));PRINT_MIN_SEC();printf("SME Mode: %o\n", seminfo.sem_perm.mode);PRINT_MIN_SEC();printf("SME Create User ID: %d\n", seminfo.sem_perm.uid);return 0;
}

运行程序时根据命令行参数的不同执行不同操作:P表示P操作 V表示V操作 I表示设置初始值为INIT_NUM D表示删除,首先执行初始化,并查询:

代码中P操作执行sops.sem_op = -1,初始值为2可以满足两次P操作,第三次P操作进入阻塞:

另起一个终端执行V操作,此时第三次P操作可以获取到信号量完成后续:

测试删除:

4、总结

本文阐述了进程间通信之信号量(System V)的定义,列举了编程中使用的接口和linux命令,编写了测试用例测试相关功能。

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

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

相关文章

2024年【N1叉车司机】新版试题及N1叉车司机模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机新版试题参考答案及N1叉车司机考试试题解析是安全生产模拟考试一点通题库老师及N1叉车司机操作证已考过的学员汇总&#xff0c;相对有效帮助N1叉车司机模拟考试题库学员顺利通过考试。 1、【多选题】《中华…

计算机服务器中了mkp勒索病毒如何解密,mkp勒索病毒解密流程

随着网络技术的不断发展与应用&#xff0c;越来越多的企业走向数字化办公模式&#xff0c;计算机极大地方便了企业的正常生产运营&#xff0c;但网络威胁的手段也不断增加。近期&#xff0c;云天数据恢复接到很多企业的求助&#xff0c;企业的计算机服务器遭到了mkp勒索病毒攻击…

重学JavaScript高级(十二):async/await-事件循环-面试高频

async/await-事件循环 前面我们学习了生成器和迭代器&#xff0c;那么在本篇文章中&#xff0c;我们主要讲解生成器与Promise的结合使用&#xff0c;从而引出async/await语法&#xff0c;同时会涉及面试中频次最高的一个知识点&#xff1a;事件循环 生成器与异步处理 首先需要…

【分布式技术专题】「Zookeeper中间件」Paxos协议的原理和实际运行中的应用流程分析

Paxo算法介绍 Paxos算法是莱斯利兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法。 Paxos产生背景 Paxos算法是基于消息传递且具有高度容错特性的一致性算法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一&#xff0c;其解决的问题就是在分…

SQL拆分字段内容(含分隔符)

问题描述&#xff1a; 在做数据迁移的过程中&#xff0c;我们希望对表中的某个字段根据分隔符进行拆分&#xff0c;得到多条数据&#xff0c;原代码有点意思&#xff0c;因此记录一下。 我们假设某条数据如下&#xff1a; IDSTRS1公司名称不能小于四个字&#xff0c;行业类别…

SSM框架,Spring-ioc的学习(上)

知识点引入 关于框架 框架( Framework )是一个集成了基本结构、规范、设计模式、编程语言和程序库等基础组件的软件系统&#xff0c;它可以用来构建更高级别的应用程序。框架的设计和实现旨在解决特定领域中的常见问题&#xff0c;帮助开发人员更高效、更稳定地实现软件开发目…

python-pandas查漏补缺

1. create labels for Series 2. 3. 4. 用平均数等去填empty的格子 5. 6. 7.

SPSS双变量相关分析

双变量相关分析通过计算皮尔逊简单相关系数、斯皮尔曼等级相关系数、肯德尔等级相关系数及其显著性水平展开。其中皮尔逊简单相关系数是一种线性关联度量&#xff0c;适用于变量为定量连续变量且服从正态分布、相关关系为线性时的情形。如果变量不是正态分布的&#xff0c;或具…

基于springboot超市进销存系统源码和论文

随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;超市进销存系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#xff0c;而超…

小游戏和GUI编程(3) | 基于 SFML 的字符阵

小游戏和GUI编程(3) | 基于 SFML 的字符阵 1. 简介 使用 EasyX 图形库时&#xff0c; 官方第一个例子是字符阵。 EasyX 不开源&#xff0c; 也不能跨平台&#xff0c; API 陈旧&#xff0c; API 是 C 而不是 C。 现在使用 SFML 来实现字符阵&#xff0c; 克服 EasyX 的这些问…

Java并发基础:LinkedTransferQueue全面解析!

内容概要 LinkedTransferQueue类实现了高效的线程间数据传递&#xff0c;支持等待匹配的生产者-消费者模式&#xff0c;基于链表的无界设计使其在高并发场景下表现卓越&#xff0c;且无需担心队列溢出&#xff0c;丰富的方法和良好的可扩展性满足了各种复杂应用场景的需求。 …

2024牛客寒假算法基础集训营3部分题解

智乃与瞩目狸猫、幸运水母、月宫龙虾 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 Ubuntu是一个以桌面应用为主的Linux发行版操作系统&#xff0c;其名称来自非洲南部祖鲁语或豪萨语的"ubuntu"一词&#xff0c;意思是"人性…

无心剑汉英双语诗《龙年大吉》

七绝龙年大吉 Great Luck in the Dragon Year 龙腾五岳九州圆 年吼佳音万里传 大漠苍鹰华夏梦 吉人天相铸奇缘 Dragon flies over five peaks watching the divine land so great and round, New Year’s call sends joyous tidal waves far across the world’s bound. The…

[office] 怎么在Excel2003菜单栏自定义一个选项卡 #其他#微信#知识分享

怎么在Excel2003菜单栏自定义一个选项卡 怎么在Excel2003菜单栏自定义一个选项卡 ①启动Excel2003&#xff0c;单击菜单栏--工具--自定义。 ②在自定义界面&#xff0c;我们单击命令标签&#xff0c;在类别中选择新菜单&#xff0c;鼠标左键按住新菜单&#xff0c;拖放到菜单栏…

SpringCloud-高级篇(十九)

我们已经学过使用 SpringAMQP去收和发消息&#xff0c;但是发和收消息是只是MQ最基本的功能了&#xff0c;在收发消息的过程中&#xff0c;会有很多的问题需要去解决&#xff0c;下面需要学习rabbitMQ的高级特性去解决 死信交换机&#xff1a;这个可以帮助我们实现消息的延迟的…

Git远程仓库的使用(Gitee)及相关指令

目录 1 远程仓库的创建和配置 1.1 创建远程仓库 1.2 设置SSH公钥 2 指令 2.1 git remote add 远端名称(一般为origin) 仓库路径 2.2 git remote 2.3 git push [-f] [--set-upstream] [远端名称 [本地分支名][:远端分支名]] 2.3 git clone url 2.4 git fetch 2.5 git p…

HCIA--NAT实验

1. 划分网段&#xff0c;配置接口IP地址&#xff0c;内网启用OSPF协议&#xff0c;并配置一对一的NAT&#xff1a; AR1配置&#xff1a; [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 10.1.1.1 24 [Huawei-GigabitEthernet0/0/0]int g0/0/1 [Huawei-GigabitEther…

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏16(附项目源码)

本节最终效果演示 【独游开发记录】一个人开发的&#xff0c;类森林&#xff0c;七日杀生存游戏 文章目录 本节最终效果演示系列目录前言泛型单例添加声音脚步声鸭子动物音效人物各种操作音效砍树音效 效果源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#x…

[经验] 喉咙沙哑的原因及应对方法是什么 #学习方法#其他#媒体

喉咙沙哑的原因及应对方法是什么 生活中&#xff0c;喉咙不舒服是很常见的情况&#xff0c;尤其是喉咙沙哑&#xff0c;让人感到特别难受&#xff0c;影响睡眠和生活质量。那么喉咙沙哑怎么办呢&#xff1f;接下来我会分享一些简单易行的方法&#xff0c;帮助你缓解这种不适感…

政安晨:示例演绎机器学习中(深度学习)神经网络的数学基础——快速理解核心概念(一){两篇文章讲清楚}

进入人工智能领域免不了与算法打交道&#xff0c;算法依托数学基础&#xff0c;很多小伙伴可能新生畏惧&#xff0c;不用怕&#xff0c;算法没那么难&#xff0c;也没那么玄乎&#xff0c;未来人工智能时代说不得人人都要了解算法、应用算法。 本文试图以一篇文章&#xff0c;…