Linux信号【systemV】

news2024/11/15 15:39:46

目录

前言

正文:

1消息队列

1.1什么是消息队列? 

1.2消息队列的数据结构 

1.3消息队列的相关接口 

1.3.1创建 

1.3.2释放 

1.3.3发送 

1.3.4接收 

1.4消息队列补充

2.信号量 

2.1什么是信号量 

2.2互斥相关概念 

2.3信号量的数据结构

2.4信号量相关接口 

2.4.1创建 

2.4.2释放

2.4.3操作

2.5信号量补充

3.深入理解 System V通信方式 

总结:



前言

在 System V 通信标准中,还有一种通信方式:消息队列,以及一种实现互斥的工具:信号量;随着时代的发展,这些陈旧的标准都已经较少使用了,但作为 IPC 中的经典知识,我们可以对其做一个简单了解,扩展 IPC 的知识栈,尤其是 信号量,可以通过它,为以后多线程学习中 POSIX 信号量的学习做铺垫

正文:

1消息队列

1.1什么是消息队列? 

 消息队列(Message Queuing)是一种比较特殊的通信方式,它不同于管道与共享内存那样借助一块空间进行数据读写,而是 在系统中创建了一个队列,这个队列的节点就是数据块,包含类型和信息

  • 假设现在进程 A、B 想要通过消息队列进行通信,首先创建一个消息队列
  • 然后进程 A 将自己想要发送给进程 B 的信息打包成数据块(其中包括发送方的信息),将数据块添加至消息队列队尾处
  • 进程 B 同样也可以向消息队列中添加数据块,同时也会从消息队列中捕获其他进程的数据块,解析后进行读取,这样就完成了通信

 

 

遍历消息队列时,存数据块 还是 取数据块 取决于 数据块中的类型 type

注意: 消息队列跟共享内存一样,是由操作系统创建的,其生命周期不随进程,因此在使用结束后需要删除

下面有关于消息队列详解的文章

 

  • 《什么是消息队列》
  • 《消息队列详解》

1.2消息队列的数据结构 

同属于 System V 标准,消息队列也有属于自己的数据结构

msg 表示 消息队列

struct msqid_ds
{
	struct ipc_perm msg_perm;	/* Ownership and permissions */
	time_t msg_stime;			/* Time of last msgsnd(2) */
	time_t msg_rtime;			/* Time of last msgrcv(2) */
	time_t msg_ctime;			/* Time of last change */
	unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
	msgqnum_t msg_qnum;			/* Current number of messages in queue */
	msglen_t msg_qbytes;		/* Maximum number of bytes allowed in queue */
	pid_t msg_lspid;			/* PID of last msgsnd(2) */
	pid_t msg_lrpid;			/* PID of last msgrcv(2) */
};

 和 共享内存 一样,其中 struct ipc_perm 中存储了 消息队列的基本信息,具体包含内容如下:

struct ipc_perm
{
	key_t __key;		  /* Key supplied to msgget(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 */
};

可以通过 man msgctl 查看函数使用手册,其中就包含了 消息队列 的数据结构信息

1.3消息队列的相关接口 

 论标准的重要性,消息队列的大小接口风格与共享内存一致,都是出自 System V 标准

1.3.1创建 

 使用 msgget 函数创建 消息队列

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

int msgget(key_t key, int msgflg);

关于 msgget 函数

 

与 共享内存 的 shmget 可以说是十分相似了,关于 ftok 函数计算 key 值,这里就不再阐述,可以在这篇文章中学习 《Linux进程间通信【共享内存】》

简单使用函数 msgget 创建 消息队列,并使用 ipcs -q 指令查看资源情况

 

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

using namespace std;

int main()
{
    //创建消息队列
    int n = msgget(ftok("./", 668), IPC_CREAT | IPC_EXCL | 0666);
    if(n == -1)
    {
        cerr << "msgget fail!" << endl;
        exit(1);
    }
    return 0;
}

程序运行后,创建出了一个 msqid 为 0 的消息队列

因为此时并 没有使用消息队列进行通信,所以已使用字节 used-bytes 和 消息数 messages 都是 0

注意:

  • 消息队列在创建时,也需要指定创建方式:IPC_CREATIPC_EXCL权限 等信息
  • 消息队列创建后,msqid也是随机生成的,大概率每次都不一样
  • 消息队列生命周期也是随操作系统的,并不会因进程的结束而释放
1.3.2释放 

 

消息队列也有两种释放方式:通过指令释放、通过函数释放

释放指令:ipcrm -q msqid 释放消息队列,其他 System V 通信资源也可以这样释放

  • ipcrm -m shmid 释放共享内存
  • ipcrm -s semid 释放信号量集

 

释放函数:msgctl(msqid, IPC_RMID, NULL) 释放指定的消息队列,跟 shmctl 删除共享内存一样

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

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

 关于 msgctl 函数

 简单回顾下参数2部分可传递参数:

 

  • IPC_RMID 表示删除共享内存
  • IPC_STAT 用于获取或设置所控制共享内存的数据结构
  • IPC_SET 在进程有足够权限的前提下,将共享内存的当前关联值设置为 buf 数据结构中的值

同样的,消息队列 = 消息队列的内核数据结构(struct msqid_ds) + 真正开辟的空间

1.3.3发送 

 利用消息队列发送信息,即 将信息打包成数据块,入队尾,所使用函数为 msgsnd

 

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

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

 关于 msgsnd 函数

 

 参数2 表示待发送的数据块,这显然是一个结构体类型,需要自己定义,结构如下:

 

struct msgbuf
{
    long mtype;    /* message type, must be > 0 */
    char mtext[1]; /* message data */
};

mtype 就是传说中数据块类型,据发送方而设定;mtex 是一个比较特殊的东西:柔性数组,其中存储待发送的 信息,因为是 柔性数组,所以可以根据 信息 的大小灵活调整数组的大小

1.3.4接收 

 消息发送后,总得接收吧,既然发送是往队尾中添加数据块,那么接收就是 从队头中取数据块,假设所取数据块为自己发送的,那么就不进行操作,其他情况则取出数据块,使用 msgrcv 函数接收信息

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

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

关于 msgrcv 函数

同样的,接收的数据结构如下所示,也包含了 类型 和 柔性数组

 

struct msgbuf
{
    long mtype;    /* message type, must be > 0 */
    char mtext[1]; /* message data */
};

1.4消息队列补充

 System V 版的 消息队列 使用起来比较麻烦,并且过于陈旧,现在已经较少使用了,所以我们不必对其进行深究,知道个大概就行了,如果实际中真遇到了,再查文档也不迟


2.信号量 

2.1什么是信号量 

 信号量(semaphore)一种特殊的工具,主要用于实现 同步和互斥

信号量 又称 信号灯,是各大高校《操作系统》课程中老师提及的高频知识点,往往伴随着 P、V 操作出现,但大多数老师都只是提及了基本概念,并未对 信号量 的本质及使用场景作出详细讲解

在正式学习 信号量 相关知识前,需要先简单了解下 互斥相关四个概念,为后续 多线程中信号量的学习作铺垫(重点)

2.2互斥相关概念 

1、并发 是指系统中同时存在多个独立的活动单元

  • 比如在多线程中,多个执行流可以同时执行代码,可能访问同一份共享资源

2、互斥 是指同一时刻只允许一个活动单元使用共享资源

  • 即在任何一个时刻,都只允许一个执行流进行共享资源的访问(可以通过加锁实现)

3、临界资源 与 临界区,多执行流环境中的共享资源就是 临界资源,涉及 临界资源 操作的代码区间即 临界区

  • 在多线程环境中,全局变量就是 临界资源,对全局变量的修改、访问代码属于 临界区

4、原子性:只允许存在 成功 和 失败 两种状态

  • 比如对变量的修改,要么修改成功,要么修改失败,不会存在修改一半被切走的状态

 所以 互斥 是为了解决 临界资源 在多执行流环境中的并发访问问题,需要借助 互斥锁 或 信号量 等工具实现 原子操作,实现 互斥

 

 

关于互斥锁(mutex) 的相关知识在 多线程 中介绍,现在先来学习 信号量,搞清楚它是如何实现 互斥 的

2.3信号量的数据结构

 下面来看看 信号量 的数据结构,通过 man semctl 进行查看

 sem 表示 信号量

struct semid_ds
{
    struct ipc_perm sem_perm; /* Ownership and permissions */
    time_t sem_otime;         /* Last semop time */
    time_t sem_ctime;         /* Last change time */
    unsigned long sem_nsems;  /* No. of semaphores in set */
};

System V 家族基本规矩,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 结构体中的内容都是一模一样的,结构上的统一可以带来管理上的便利,具体原因可以接着往下看

2.4信号量相关接口 

2.4.1创建 

 信号量的申请比较特殊,一次可以申请多个信息量,官方称此为 信号量集,所使用函数为 semget

 

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

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

关于 semget 函数

除了参数2,其他基本与另外俩兄弟一模一样,实际传递时,一般传 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;
}

程序运行后,创建了一个 信号量集nsems 为 1,表示在当前 信号量集 中只有一个 信号量

  • 信号量集在创建时,也需要指定创建方式:IPC_CREATIPC_EXCL权限 等信息
  • 信号量集创建后,semid也是随机生成的,大概率每次都不一样
  • 信号量集生命周期也是随操作系统的,并不会因进程的结束而释放
2.4.2释放

老方法: 指令释放:直接通过指令 ipcrm -s semid 释放信号量集(略)

通过函数释放:semctl(semid, semnum, IPC_RMID),信号量中的控制函数有一点不一样

 

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

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

 关于 semctl 函数

注意:

  • 参数2 表示信号量集中的某个信号量编号,从 1 开始编号
  • 参数3 中可传递的动作与共享内存、消息队列一致
  • 参数4 就像 printf 和 scanf 中最后一个参数一样,可以灵活使用
2.4.3操作

信号量的操纵比较ex,也比较麻烦,所以仅作了解即可

使用 semop 函数对 信号量 进行诸如 +1-1 的基本操作

 

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

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

 关于 semop 函数

重点在于参数2,这是一个结构体,具体成员如下:

unsigned short sem_num;  /* semaphore number */
short          sem_op;   /* semaphore operation */
short          sem_flg;  /* operation flags */

其中包含信号量编号、操作等信息,需要我们自己设计出一个结构体,然后传给 semop 函数使用

可以简单理解为:sem_op 就是要进行的操作,如果将 sem_op 设为 -1,表示信号量 -1(申请),同理 +1 表示信号量 +1(归还)

2.5信号量补充

 

信号量 是实现 互斥 的其中一种方法,具体表现为:资源申请,计数器 -1,资源归还,计数器 +1,只有在计数器不为 0 的情况下,才能进行资源申请,可以设计 二元信号量 实现 互斥

System V 中的 信号量 操作比较麻烦,但 信号量 的思想还是值得一学的,等后面学习 多线程 时,也会使用 POSIX 中的 信号量 实现 互斥,相比之下,POSIX 版的信号量操作要简单得多,同时应用也更为广泛

因为 信号量 需要被多个独立进程看到,所以 信号量 本身也是 临界资源,不过它是 原子 的,所以可以用于 互斥

多个独立进程看到同一份资源,这就是 IPC 的目标,所以 信号量 被划分至进程间通信中

 


3.深入理解 System V通信方式 

 不难发现,共享内存、消息队列、信号量的数据结构基本一致,并且都有同一个成员 struct ipc_perm,所以实际对于 操作系统 来说,对 System V 中各种方式的描述管理只需要这样做

  • 将 共享内存、消息队列、信号量对象描述后,统一存入数组中
  • 再进行指定对象创建时,只需要根据 ipc_id_arr[n]->__key 进行比对,即可当前对象是否被创建!
  • 因为 struct shmid_ds 与 struct ipc_perm shm_perm 的地址一致(其他对象也一样),所以可以对当前位置的指针进行强转:((struct shmid_ds)ipc_id_arr[0]) 即可访问 shmid_ds 中的成员,这不就是多态中的虚表吗?

这样一来,操作系统可以只根据一个地址,灵活访问 两个结构体中的内容,比如 struct ipc_perm shm_perm 和 struct shmid_ds,并且操作系统还把多种不同的对象,描述融合入了一个 ipc_id_arr 指针数组中,真正做到了 高效管理

注:默认 ipc_id_arr[n] 访问的是 struct ipc_perm 中的成员

注:上述图示只是一个草图,目的是为了辅助理解原理,并非操作系统中真实样貌

操作系统在进行比较判断时,如何判断类型呢?

这就是操作系统设计的巧妙之处了,ipc_id_arr 没那么简单,它会存储对象的相应类型信息
通过下标(id) 访问对象,这与文件系统中的机制不谋而合,不过实现上略有差异,间接导致 System V 的管理系统被边缘化(历史选择了文件系统)

shmid、msqid 和 semid 都是 ipc_id_arr 的下标,为什么值很大呢?

在进行查找时,会将这些 id % 数组大小 进行转换,确保不会发生越界,事实上,这个值与开机时间有关,开机越长,值越大,当然到了一定程度后,会重新轮回

总结:

上面就是关于信号量部分的内容,有个大概了解就行。

 

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

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

相关文章

【高阶数据结构】LRUCache

文章目录 1. 什么是LRU Cache2. LRU Cache的实现3. LinkedHashMap4. LRU Cache OJ题4.1 题目要求4.2 解题思路4.3 代码实现4.3.1 Java代码一4.3.2 Java代码二 1. 什么是LRU Cache LRUCache&#xff0c;全称为Least Recently Used Cache&#xff0c;即最近最少使用缓存&#xf…

基于springboot+vue的纺织品企业财务管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

mac 安装hbuilderx

下载 HBuilderX下载地址: 下载地址 选额mac版本点击下载 安装 如图&#xff0c;将HBuilderX拖到Applications&#xff0c;才是正确的安装姿势。 MacOSX&#xff0c;软件必须安装到/Applications目录&#xff0c;如未安装到此目录&#xff0c;可能会出现插件安装失败、项目创建…

揭秘Java性能调优的层次 | 综合多方向提升应用程序性能与系统高可用的关键(架构层次规划)

揭秘性能调优的层次 | 综合多方向提升应用程序性能与系统的高可用 前言介绍调优层次调优 — 设计案例说明 - 操作轮询控制事件驱动 调优 — 代码案例说明 - ArrayList和LinkedList性能对比案例说明 - 文件读写实现方式的性能对比 调优 — JVMJVM架构分布JVM调优方向**JVM垃圾回…

Linux搭建SFTP服务器

案例&#xff1a;搭建SFTP服务器 SFTP&#xff08;SSH文件传输协议&#xff09; SFTP&#xff08;SSH文件传输协议&#xff09;是一种安全的文件传输协议&#xff0c;用于在计算机之间传输文件。它基于SSH&#xff08;安全外壳协议&#xff09;的子系统&#xff0c;提供了加密的…

EchoServer回显服务器简单测试

目录 工具介绍 工具使用 测试结果 工具介绍 github的一个开源项目,是一个测压工具 EZLippi/WebBench: Webbench是Radim Kolar在1997年写的一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL&#xff0c;测试网站在压力下工作的…

动态住宅IP vs 静态住宅IP,如何选择适合你的海外住宅IP?

随着数字时代的发展&#xff0c;网络已经成为了我们日常生活中不可或缺的一部分。在海外留学、旅游、工作或者进行电子商务等活动时&#xff0c;一个合适的住宅IP可以帮助我们保护个人隐私、确保网络连接的稳定性、提高在线服务的可靠性等。因此&#xff0c;选择适合自己的住宅…

ChatGPT科研与AI绘图及论文高效写作教程

原文链接&#xff1a;ChatGPT科研与AI绘图及论文高效写作教程 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电…

vos3000外呼系统如何修改话机注册端口

本文以vos3000为例&#xff0c;其他产品替换对应产品名称即可 修改配置文件地址 /home/kunshi/mbx3000/etc/softswitch.conf H323_RAS_PORT1719 H323 注册端口&#xff0c;可以用逗号&#xff08;,&#xff09;分隔多个端口 H323_RC4_RAS_PORT3719 H323 加密注册端口&#x…

redis03 八种数据类型

思维草图 String类型 字符串类型&#xff0c;是redis中最简单的存储类型&#xff0c;可以包含任何数据&#xff0c;例如jpg图片或者序列化的对象等&#xff0c;底层都是以字节数组形式存储&#xff0c;最大能存储512MB的数据。 常用命令 KEY命名规范 加前缀&#xff0c;分…

Vue3 循环渲染 v-for

v-for 指令&#xff1a;用于循环渲染列表数据。 v-for 指令&#xff1a;可以循环数组、对象、字符串【不常用】、指定次数【很少用】。 key 属性&#xff1a;用于给标签添加一个唯一的标识。 key 属性&#xff1a;推荐使用 id、手机号、身份证号、学号 等唯一值。 注&#…

如何查看docker容器里面运行的nginx的配置文件哪

要查看Docker容器内运行的Nginx配置文件的位置&#xff0c;你可以通过进入容器的shell环境来直接查看。Nginx的默认配置文件通常位于/etc/nginx/nginx.conf&#xff0c;而网站特定的配置文件通常位于/etc/nginx/conf.d/目录中。以下是步骤来查看这些配置文件&#xff1a; 步骤…

挑战杯 基于机器视觉的车道线检测

文章目录 1 前言2 先上成果3 车道线4 问题抽象(建立模型)5 帧掩码(Frame Mask)6 车道检测的图像预处理7 图像阈值化8 霍夫线变换9 实现车道检测9.1 帧掩码创建9.2 图像预处理9.2.1 图像阈值化9.2.2 霍夫线变换 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分…

软考54-上午题-【数据库】-关系模式的范式-真题

一、范式总结 第一步&#xff0c;先求候选码&#xff0c;由此得到&#xff1a;主属性、非主属性。 二、判断部分函数依赖的技巧 【回顾】&#xff1a;部分函数依赖 &#xff08;X&#xff0c;Y&#xff09;——>Z&#xff1b; X——>Z 或者 Y——>Z 题型&#xff1a;给…

Vue2:路由history模式的项目部署后页面刷新404问题处理

一、问题描述 我们把Vue项目的路由模式&#xff0c;设置成history 然后&#xff0c;build 并把dist中的代码部署到nodeexpress服务中 访问页面后&#xff0c;刷新页面报404问题 二、原因分析 server.js文件 会发现&#xff0c;文件中配置的路径没有Vue项目中对应的路径 所以…

【打工日常】使用docker部署在线Photopea用于linux下替代ps

一、Photopea介绍 linux没有ps适配&#xff0c;对于有时候工作来说确实不方便&#xff0c;我找了很久&#xff0c;才找到了一款功能可以跟ps接近的在线软件&#xff0c;使用docker部署就可以了。它是ps的最佳替代品之一&#xff0c;其界面几乎与ps相同&#xff0c;只不过它是在…

Ban for 1 day (wangzherongyao) 2024.03.02

王者荣耀禁赛1天 单排真的要保持【心态】&#xff0c;即便队友是这种&#xff0c;也要克制&#xff0c;不然接着就开始【连败】。 为什么我玩射手和法师喜欢提早第一件第二件出【梦魇】和【制裁】&#xff0c;因为对面有回复英雄就是一个风险&#xff0c;早做应对&#xff01;…

降低85%的gc发生率:ES的GC调优实践!

#大数据/ES #经验 #性能 ES的服务日志出现一些gc overhead现象&#xff0c;经过调优对比&#xff0c;gc发生率显著下降了85%&#xff0c;分享参数如下&#xff1a; ES的G1GC参数&#xff08;多实例&#xff09; -XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:InitiatingHeapOccu…

拒绝机械风,让ChatGPT像真人一样对话

拒绝机械风&#xff0c;让ChatGPT像真人一样对话 在这个信息爆炸的时代&#xff0c;人工智能技术的快速发展让我们的生活变得更加便捷。 特别是在自然语言处理领域&#xff0c;ChatGPT的出现无疑是一次革命性的进步。 然而&#xff0c;虽然ChatGPT在很多方面表现出了惊人的能…

蜘蛛蜂优化算法SWO求解不闭合SD-MTSP,可以修改旅行商个数及起点(提供MATLAB代码)

1、蜘蛛蜂优化算法SWO 蜘蛛蜂优化算法&#xff08;Spider wasp optimizer&#xff0c;SWO&#xff09;由Mohamed Abdel-Basset等人于2023年提出&#xff0c;该算法模型雌性蜘蛛蜂的狩猎、筑巢和交配行为&#xff0c;具有搜索速度快&#xff0c;求解精度高的优势。VRPTW&#x…