【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 0x66

key_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.mfbz.cn/a/611341.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(九)JSP教程——pageContext对象

pageContext对象是由JSP容器创建并初始化的&#xff0c;相当于当前页面的容器&#xff0c;它可以访问当前页面中的所有对象。它的主要作用是为JSP页面包装上下文&#xff0c;并用于管理属于JSP的特殊可见部分中已命名对象的访问。 一般情况下&#xff0c;使用该对象的应用并不多…

自动驾驶主流芯片及平台架构(三)低算力平台

前面有提到&#xff0c;自动驾驶等级每增加一级&#xff0c;所需要的芯片算力就会呈现十数倍的上升&#xff0c;L2级自动驾驶的算力需求仅要求2-2.5TOPS&#xff0c;但是L3级自动驾驶算力需求就需要20-30TOPS,到L4级需要200TOPS以上&#xff0c;L5级别算力需求则超过2000TOPS。…

【Docker】Docker部署Java程序

Maven中使用打包插件 <build><finalName>duanjian</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass…

让GPT们成为我们的小助手:使用ChatGPT来生成测试用数据

让GPT们成为我们的小助手 任务&#xff1a;帮忙生成测试数据 今天本来想做一个测试&#xff0c;所以需要一些测试数据。为了让测试显得更真实&#xff0c;所以希望测试数据看上去就是一份真实的数据&#xff0c;所以我就希望ChatGPT&#xff08;这里是代指&#xff0c;我有使…

高校教务选课管理系统开发方案

一、项目背景与目标 &#xff08;一&#xff09;项目背景 随着高校教育规模的扩大&#xff0c;教务管理变得越来越复杂&#xff0c;传统的手工管理方式已经无法满足现代高校的需求。因此&#xff0c;开发一套高效、便捷的高校教务选课管理系统显得尤为重要。该系统将涵盖学生…

控制情绪是交易成功的根本?大错特错

布雷特斯坦伯格&#xff08;Brett Steenbarger&#xff09;是一位在美国享有盛誉的交易心理学专家&#xff0c;他曾在华尔街的多个顶尖培训中心担任交易员的心理指导。身为心理学教授兼高级交易员的布雷特在交易心理方面要比别人了解得多。而且小编觉得做一个成功的交易员只靠交…

NSS刷题

1、[SWPUCTF 2021 新生赛]gift_f12 打开题目后查看源码无发现&#xff0c;用f12发现flag 2、[GDOUCTF 2023]hate eat snake 打开链接是一个贪吃蛇小游戏&#xff0c;f12找到js文件中有一个speed的语句&#xff0c;该语句的作用是使速度增加&#xff0c;因此&#xff0c;将该语…

【全开源】Java外卖霸王餐免费吃外卖小程序+APP+公众号+H5多端霸王餐源码

一、特色功能 霸王餐活动管理&#xff1a;允许商家发布和管理霸王餐活动&#xff0c;包括设置活动时间、具体优惠、活动规则等。用户参与与浏览&#xff1a;用户可以在小程序中浏览霸王餐活动列表&#xff0c;查看活动的详情信息&#xff0c;如商品或服务的免费赠送、活动规则…

一文带你了解军用电源绝缘性能测试规范和标准

军用电源是指主要用于军事、航空航天等领域的电源模块&#xff0c;因其良好的稳定性和可靠性也在通信、交通、航空航海、加工工业等领域广泛应用。因此&#xff0c;对于军用电源的性能要求比较严格&#xff0c;性能测试是确保电源质量的关键环节。 那么&#xff0c;在测试军品电…

【vulhub靶场】Apache 中间件漏洞复现

【vulhub靶场】Apache 中间件漏洞复现 一、Apache HTTPD 换行解析漏洞&#xff08;CVE-2017-15715&#xff09;1. 漏洞详情2. 影响版本3. 漏洞复现 二、Apache多后缀解析漏洞&#xff08;apache_parsing_vulnerability&#xff09;1. 漏洞详情2. 漏洞复现 三、Apache HTTP Serv…

一篇详解Git版本控制工具

华子目录 版本控制集中化版本控制分布式版本控制 Git简史Git工作机制Git和代码托管中心局域网互联网 Git安装基础配置git的--local&#xff0c;--global&#xff0c;--system的区别 创建仓库方式1git init方式2git clone git网址 工作区&#xff0c;暂存区&#xff0c;本地仓库…

将AI融入项目开发工作中去吧

目录 1.提高编写开发日报的效率 2.提高编写代码注释的效率 3.提高代码重构的效率 4.编写测试用例及测试报告 5. 协助进行代码走查与工作量分析 在AI元年后&#xff0c;作为一名程序员&#xff0c;相信各位友友已经深切地感受到了它带来的变革。作为一个从小白到资深码农的…

canvas识别路线

theme: jzman 视频说明 jvideo 前言 效果一 技术栈 htmljavascriptcsscanvas 项目主要功能上传一张地图&#xff0c;或者迷宫地图&#xff0c;通过canvas的一系列操作&#xff0c;并指定一个起点和终点&#xff0c;并找到到达终点最近的路线 迷宫找出口效果 正文 加载图像 首先…

芋道系统springcloud模块启动报错,枚举类不能为空

问题描述&#xff1a; Error starting ApplicationContext. To display the conditions report re-run your application with debug enabled. 2024-05-10 15:50:15.756 | ERROR 9120 | main [TID: N/A] o.s.b.d.LoggingFailureAnalysisReporter | ************************…

【C++】详细版 RAII技术的应用之智能指针(智能指针发展历程和简单模拟实现介绍)

目录 前言 一、智能指针有什么用&#xff1f; 二、什么是RAII(智能指针的底层思想)&#xff1f; 三、智能指针的发展历程以及模拟实现 1.auyo_ptr&#xff08;C98&#xff09; 2.unique_ptr&#xff08;C11&#xff09; 3.shared_ptr&#xff08;C11&#xff09; 前言 C中…

面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析

一、前言 记录时间 [2024-05-10] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 11&#xff1a;Java 方法相关内容&#xff0c;方法的设计原则&#xff0c;以及方法的定义和调用 面向对象 01&#xff1a;Java 面向对…

使用com.google.common.collect依赖包中的Lists.transform()方法转换集合对象之后,修改集合中的对象属性,发现不生效

目录 1.1、错误描述 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;模拟代码 &#xff08;3&#xff09;运行结果 1.2、解决方案 1.1、错误描述 最近在开发过程中&#xff0c;使用到了com.google.common.collect依赖包&#xff0c;通过这个依赖包中提供的…

4D 成像毫米波雷达:新型传感器助力自动驾驶

1 感知是自动驾驶的首要环节&#xff0c;高性能传感器必不可少 感知环节负责对侦测、识别、跟踪目标&#xff0c;是自动驾驶实现的第一步。自动驾驶的实现&#xff0c;首先要能够准确理解驾驶环境信息&#xff0c;需要对交通主体、交通信号、环境物体等信息进行有效捕捉&#x…

2024-AIDD-人工智能药物设计-AlphaFold3

AlphaFold3&#xff5c;万字长文解读 AlphaFold3预测所有分子相互作用准确结构 AlphaFold3 自2021年AlphaFold2问世以来&#xff0c;科研工作者们便开始利用这一蛋白结构预测模型来详细描绘众多蛋白质的结构、探索新药。近日&#xff0c;Google DeepMind公司推出了其最新产品…
最新文章