【Linux】18. 进程间通信 --- System V IPC(选学)

System V IPC

  • System V 消息队列
  • System V 共享内存
  • System V 信号量

system V 共享内存

在这里插入图片描述
共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核。
换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据

共享内存示意图

在这里插入图片描述

共享内存数据结构

struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */unsigned short shm_unused; /* compatibility */void *shm_unused2; /* ditto - used by DIPC */void *shm_unused3; /* unused */
};

共享内存函数

shmget函数

功能:用来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

在这里插入图片描述
深入理解key值:
OS需要对共享内存进行管理,既然要管理就遵循先描述再组织的原则
所以共享内存 = 内存块+共享内存的相关属性
共享内存的相关属性就是上述的struct shmid_ds数据结构进行管理,而key值就存储在shm_perm当中

shmat函数

功能:将共享内存段连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
说明
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr -
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

shmdt函数

功能:将共享内存段与当前进程脱离
原型
int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

shmctl函数

功能:用于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

在这里插入图片描述

查看IPC资源命令:

在这里插入图片描述
在这里插入图片描述

代码实现

通过代码的方式进一步认清共享内存的使用

// comm.hpp 文件
#ifndef _COMM_HPP_
#define _COMM_HPP_#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>#define MAX_SIZE 4096// 这里的PATHNAME为当前路径
#define PATHNAME "."
// 这里的PROJ_ID为随机值
#define PROJ_ID 0x66key_t getKey()
{// ftok函数创建key值// ftok函数根据所提供的路径和值会通过算法确定一个唯一值// 当server和client看到同一个key值 也就意味着看到同一份共享内存key_t k = ftok(PATHNAME, PROJ_ID);if(k == -1){std::cerr << errno << ": " << strerror(errno) << std::endl;exit(1);}return k;
}int getShmHelper(key_t k, int flags)
{// shmget函数创建共享内存int shmid = shmget(k, MAX_SIZE, flags);if (shmid < 0){std::cerr << errno << ": " << strerror(errno) << std::endl;exit(2);}return shmid;
}int getshm(key_t k)
{return getShmHelper(k, IPC_CREAT);
}int createShm(key_t k)
{// 创建新的shm权限为0600 只有自己有读写权限return getShmHelper(k, IPC_CREAT | IPC_EXCL | 0600);
}#endif
// shm_server.cc 文件
#include "comm.hpp"// server端进行创建和删除共享内存int main()
{key_t k = getKey();printf("key:0x%x\n", k);int shmid = createShm(k);printf("shmid:%d\n", shmid);return 0;
}

在这里插入图片描述

// shm_client.cc文件
#include "comm.hpp"int main()
{key_t k = getKey();printf("key:0x%x\n", k);int shmid = getshm(k);printf("shmid:%d\n", shmid);return 0;
} 

在这里插入图片描述

[hx@iZ0jl69kyvg0h181cozuf5Z shared_memory]$ ./shm_server 
key:0x66010470
17: File exists

出现 File exists 错误 说明文件已经存在
说明共享内存的生命周期是随OS的,而不是随进程的(不像管道,当没有文件描述符指向管道文件时,会自行关闭)

// comm.hpp文件
void *attachShm(int shmid)
{void *mem = shmat(shmid, nullptr, 0);// 这里为啥要强转成longlong类型呢?// 因为当前OS为64位 指针占8个字节if ((long long)mem == -1L){// 挂接失败std::cerr << "shmat: " << errno << strerror(errno) << std::endl;exit(3);}return mem;
}void detachShm(void *start)
{if (shmdt(start) == -1){// 去关联失败std::cerr << "shmdt: " << errno << strerror(errno) << std::endl;}
}void delShm(int shmid)
{if (shmctl(shmid, IPC_RMID, nullptr) == -1){std::cerr << "shmctl: " << errno << strerror(errno) << std::endl;}
}
// shm_client.cc
#include "comm.hpp"int main()
{key_t k = getKey();printf("key:0x%x\n", k);int shmid = getshm(k);printf("shmid:%d\n", shmid);sleep(5);char *start = (char*)attachShm(shmid);printf("attach success, address start: %p\n", start);sleep(5);detachShm(start);return 0;
} 
// shm_server.cc
#include "comm.hpp"// server端进行创建和删除共享内存int main()
{// 创建key_t k = getKey();printf("key:0x%x\n", k);int shmid = createShm(k);printf("shmid:%d\n", shmid);sleep(5);// 挂接// 这里为啥用start命名呢?// 因为挂接成功后返回的是进程地址空间的起始地址// 进一步加深先描述再组织的概念// OS不会直接让用户直接对共享内存进行操作,// 要先管理进进程地址空间中 char *start = (char*)attachShm(shmid);printf("attach success,address start:%p\n",start);sleep(5);// 去关联detachShm(start);sleep(10);// 删除共享内存delShm(shmid);return 0;
}

观察上述代码现象,如下所示:
在这里插入图片描述
进行最后一步通信:

// shm_server文件//通信while(true){//直接从start中读取数据printf("client say:%s\n",start);sleep(1);}
// shm_client文件//通信const char* message = "hello server,我是另一个进程,正在与你进行通信";pid_t id = getpid();int cnt = 1;while(true){sleep(1);// snprintf函数直接往start当中写入数据snprintf(start,MAX_SIZE,"%s[pid:%d][消息编号:%d]",message,id,cnt++);}

通信成功!!!
在这里插入图片描述
在这里插入图片描述
共享内存的缺点:
没有进行同步和互斥的操作,没有对数据做任何保护措施!
如果写入的很慢,读取的很快就总是会读取到重复冗余数据
在这里插入图片描述
进程独立性的原因:1. 各进程代码和数据独立 2.内核数据结构独立 3. 页表映射独立

system V 消息队列

在这里插入图片描述

system V 信号量

什么是信号量?

信号量的本质就是计数器,通常用来表示公共资源当中资源数量的多少

既然是计数器,那么能不能在代码中定义一个全局的count来进行统计呢?
答案:不能。如果是父子进程,往往会发生写时拷贝,二者看到的就不是同一份资源。(无法看到同一个count)
如果是毫不相干的进程,那么就更加需要提供通信技术来保证看到的是同一份资源

什么是公共资源?

公共资源就是指可以被多个进程同时进行访问的资源 (像:管道/共享内存/消息队列…)
而需要访问公共资源又会引发新的问题
在访问没有保护的公共资源就会出现数据不一致问题(类似于MySQL事务当中的脏读情况)
(假设现在的场景:输入abcd且abcd只有连在一起才有意义,但是输入一半就被另一个进程读取了)

为什么要让不同的进程看到同一份资源呢?

因为想要实现通信(进程间实现协同),但是进程具有独立性,如何让独立的进程实现协同呢? 让进程看到同一份资源
提出方法->引入了新的问题(数据不一致问题)

临界资源:未来被保护起来的公共资源
进程的大部分资源是独立的,只有少部分资源属于多进程共享,被多进程共享的资源称之为公共资源 而被保护起来的就叫做临界资源
资源(内存,文件,网络等)创建出来是要被使用的。

资源如何被进程使用呢?

一定是该进程有对应的代码来访问这部分临界资源: 临界区 非临界区

总结:
多进程在通信时本质是要看到一份公共的资源 ,这份公共资源未来被保护起来称其为临界资源,
访问临界资源的代码称之为临界区,不访问临界资源的代码称之为非临界区

保护资源的策略分为两种:互斥 && 同步(同步这里不涉及)

互斥: 当两个人同时访问一份资源时,只有当你访问完我才能访问
要么不做,要做就做完 只有两态的这种情况称之为原子性

共享资源的使用方式:1. 作为一个整体使用(管道/共享内存) 2. 划分为一个个的资源子部分使用(信号量)
对于共享资源划分成子部分(可以供不同的进程使用 – 并发) 而整体使用就是互斥串行(效率低)
在这里插入图片描述
所有的进程在访问公共资源之前,都必须先申请sem信号量 (先申请sem信号量的前提是所有进程必须先得看到同一个信号量)
信号量本身作为公共资源,信号量是不是也要保证自己的安全呢?
–,++信号量必须保证自身操作的安全性。
–,++操作是原子(只有两态:成功 or 失败)

申请信号量成功时相当于预定了共享资源当中的某一部分小资源,允许进程进行访问
如果申请信号量不成功,就不允许进程进入共享资源当中,进而达到保护共享资源以及其他进程的目的

通过计数器的方式,对临界资源进行保护 这种计数器我们称之为信号量

申请信号量后,进程可能会访问同一份子资源,需要程序员自己写代码保护资源

接口使用

在这里插入图片描述
在这里插入图片描述

system V 资源总结:

共享内存,消息队列,信号量,IPC资源 都是先描述再组织
操作系统为了维护IPC资源必须花费大量的数据结构来描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

云南区块链商户平台优化开发

背景 云南区块链商户平台是全省统一区块链服务平台。依托于云南省发改委、阿里云及蚂蚁区块链的国内首个省级区块链平台——云南省区块链平台同步上线&#xff0c;助力数字云南整体升级。 网页版并不适合妈妈那辈人使用&#xff0c;没有记忆功能&#xff0c;于是打算自己开发…

k8s介绍

一、前言 Kubernetes&#xff08;通常简称为 K8s&#xff09;是一个开源的容器编排平台&#xff0c;用于自动化部署、扩展和管理容器化应用程序&#xff0c;它提供了丰富的功能使得用户能够轻松地管理大规模的容器集群&#xff0c;包括自动化部署和扩展、服务发现和负载均衡、存…

漫威争锋Marvel Rivals怎么搜索 锁区怎么搜 游戏搜不到怎么办

即将问世的《漫威争锋》&#xff08;Marvel Rivals&#xff09;作为一款万众期待的PvP射击游戏新星&#xff0c;荣耀携手漫威官方网站共同推出。定档5月11日清晨9时&#xff0c;封闭Alpha测试阶段将正式揭开序幕&#xff0c;持续时间长达十天之久。在此首轮测试窗口&#xff0c…

一个开源即时通讯源码

一个开源即时通讯源码 目前已经含服务端、PC、移动端即时通讯解决方案&#xff0c;主要包含以下内容。 服务端简介 不要被客户端迷惑了&#xff0c;真正值钱的是服务端&#xff0c; 服务是采用Java语言开发&#xff0c;基于spring cloud微服务体系开发的一套即时通讯服务端。…

栈结构(c语言)

1.栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&am…

STM32的ADC详解

ADC即模拟数字转换器&#xff0c;通常用于将外部的模拟量信号转换为数字信号。STM32的ADC是12位逐次逼近型的模拟数字转换器&#xff0c;最大可以计数到4095&#xff0c;有18个通道&#xff0c;16个外部通道和2个内部通道。 ADC框图 ADC的功能框图可以分为七个部分&#xff1a…

记一次springboot jpa更新复杂几何类型报错Only simple geometries should be used

问题&#xff1a; 更新数据时&#xff0c; 几何字段MultiPolygon类型时报错&#xff1b; java.lang.IllegalStateException: Only simple geometries should be used 几何字段Point类型时不报错&#xff1b; 新增时字段存在MultiPolygon不报错。 查看日志可知&#xff0c;…

vscode 使用正则搜索

ctrl c 复制&#xff0c;内容如下&#xff1a; Vue3简介创建Vue3工程Vue3核心语法路由pinia组件通信其它 APIVue3新组件

Go 单元测试完全指南(一)- 基本测试流程

为什么写单元测试&#xff1f; 关于测试&#xff0c;有一张很经典的图&#xff0c;如下&#xff1a; 说明&#xff1a; 测试类型成本速度频率E2E 测试高慢低集成测试中中中单元测试低快高 也就是说&#xff0c;单元测试是最快、最便宜的测试方式。这不难理解&#xff0c;单元…

Baidu Comate:让编码实现无限可能

目录 1 背景介绍2 快速入门2.1 智能推荐功能2.2 智能生成功能2.2.1 智能注释2.2.2 智能生成2.2.3 智能调优2.2.4 代码解释 3 高兼容性4 即刻体验 1 背景介绍 Baidu Comate&#xff08;智能代码助手&#xff09;是基于文心大模型&#xff0c;结合百度积累多年的编程现场大数据和…

【MySQL数据库】丨一文详解 JdbcTemplate(Spring中的CRUD)

前言 JdbcTemplate 是 Spring框架 中提供的一个对象&#xff0c;用于简化JDBC操作。它使得数据库操作变得更为简单和方便&#xff0c;大大提高了开发效率。 文章目录 前言为何要使用JdbcTemplate在JdbcTemplate中执行SQL语句的方法大致分为3类&#xff1a;案例代码 JdbcTemplat…

word 毕业论文格式调整

添加页眉页脚 页眉 首先在页面上端页眉区域双击&#xff0c;即可出现“页眉和页脚”设置页面&#xff1a; 页眉左右两端对齐 如果想要页眉页脚左右两端对齐&#xff0c;可以选择添加三栏页眉&#xff0c;然后将中间那一栏删除&#xff0c;即可自动实现左右两端对齐&#x…

Linux 操作系统TCP、UDP

1、TCP服务器编写流程 头文件&#xff1a; #include <sys/socket.h> 1.1 创建套接字 函数原型&#xff1a; int socket(int domain, int type, int protocol); 参数&#xff1a; domain: 网域 AF_INET &#xff1a; IPv4 AF_INET6 &a…

fswatch工具:跟踪Linux中的文件和目录更改

fswatch是一个跨平台的文件更改监视器&#xff0c;当指定文件或目录的内容被更改或修改时&#xff0c;它会收到通知警报。 fswatch在不同的操作系统上执行多种类型的监视器&#xff0c;例如&#xff1a; 基于 Apple OS X 的文件系统事件 API 构建的监视器。基于kqueue的监视器…

WPF之DataGird应用

1&#xff0c;DataGrid相关属性 GridLinesVisibility&#xff1a;DataGrid网格线是否显示或者显示的方式。HorizontalGridLinesBrush&#xff1a;水平网格线画刷。VerticalGridLinesBrush&#xff1a;垂直网格线画刷。HorizontalScrollBarVisibility&#xff1a;水平滚动条可见…

ASP.NET MVC 如何使用 Form Authentication?

前言 .NET 的 Form Authentication 是一种基于表单的简单且灵活的身份验证机制&#xff0c;用户通过输入用户名和密码来登录应用程序&#xff0c;并且通过配置来控制用户访问权限。 在使用 Form Authentication 时&#xff0c;我们需要在 web.config 文件中配置身份验证和授权…

Spring Cloud Consul 4.1.1

该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习惯用法&#xff0c;为 Spring Boot 应用程序提供 Consul 集成。通过一些简单的注释&#xff0c;您可以快速启用和配置应用程序内的常见模式&#xff0c;并使用基于 Consul 的组件构建大型分布式系统。提供的模式…

Spark云计算平台Databricks使用,第一个Spark应用程序WordCount

1 上传文件 上传words.txt文件&#xff1a;Spark云计算平台Databricks使用&#xff0c;上传文件-CSDN博客 上传的文件的路径是/FileStore/tables/words.txt&#xff0c;保存在AWS的S3 hello world hello hadoop hello world hello databricks hadoop hive hbase yarn spark …

利用BACnet分布式IO控制器优化Niagara楼宇自动化系统

在智能建筑领域&#xff0c;随着物联网技术的飞速发展&#xff0c;如何实现高效、灵活且安全的楼宇自动化控制成为了行业关注的焦点。BACnet IP分布式远程I/O模块&#xff0c;作为这一领域的创新成果&#xff0c;正逐渐成为连接智能建筑各子系统的关键桥梁&#xff0c;尤其在与…

springboot -多数据源管理方案

多数据源的配置有多种方式 方式一 、依赖dataSource的配置 1.建立多数据源配置 spring:# 数据源配置datasource:pdm:driver-class-name: oracle.jdbc.driver.OracleDriverjdbc-url: jdbc:oracle:thin:10.216.xxx.xxx:3000:orclusername: cfpdmpassword: capecapp:driver-cla…