Linux进阶-ipc共享内存

目录

共享内存

shmget():创建或获取共享内存

shmat():映射

shmdt():解除映射

shmctl():获取或设置属性

sem.h文件

sem.c文件

shm.c文件

Makefile文件

执行过程


共享内存

共享内存:将内存进行共享,它允许多个不相关的进程访问同一个逻辑内存,直接将一块裸露的内存放在需要数据传输的进程前,供进程使用。

因此,共享内存是效率最高的一种IPC通信机制,可以在多个进程间共享和传递数据,进程间需要共享的数据被放在共享内存区域所有需要访问该共享内存的进程都要把该共享区域映射到本进程的地址空间中,因此所有进程都可访问共享内存的地址。

但是,共享内存需要进程自己去维护,如同步、互斥等。如进程1在读取共享内存的数据时,进程2却修改了共享内存的数据,这会导致数据混乱。因此共享内存属于临界资源,在某一时刻只能有一个进程对其操作(读写)。共享内存一般不能单独使用,而是配合信号量、互斥锁等协调机制,让各个进程在高效交换数据时,不会发生数据践踏、破坏等行为。

共享内存思想:进程间虚拟内存空间本来相互独立,不能相互访问,但是可以通过某种方式使得相同的一块物理内存多次映射到不同的进程虚拟空间中,相当于多个进程的虚拟内存空间部分重叠在一起。共享内存少了拷贝的操作,减少了系统开销,因此效率极高

shmget():创建或获取共享内存

shmget()函数会创建或获取一个共享内存对象,并返回共享内存标识符。

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
/*
key:共享内存的标识符IPC_PRIVATE:创建一块新的共享内存0:当shmflg参数设置了IPC_PRIVATE标志,则将创建一块新的共享内存大于0的32位整数:根据shmflg参数来确定操作
size:要创建共享内存的大小,所有的内存分配操作都是以页为单位的,所有即使只申请一个字节的内存,内存也会分配一页。
shmflg:表示创建的共享内存的模式标志参数。标志 | modeIPC_CREAT:如果内核中不存在关键字与key相等的共享内存,则新建一个共享内存;如果存在则返回此共享内存的标识符。IPC_EXCL:如果内核中不存在关键字与key相等的共享内存,则新建一个共享内存;如果存在则报错SHM_HUGETLB:使用“大页面”来分配共享内存,所谓的“大页面”指的是内核为了提高程序性能,对内存实行分页管理时,采用比默认尺寸(4KB)更大的分页,以减少缺页中断。 Linux 内核支持以 2MB 作为物理页面分页的基本单位。SHM_NORESERVE:不在交换分区中为这块共享内存保留空间。
返回值:共享内存的ID。
*/

当调用shmget()函数失败时将产生错误代码:

        EACCES:指定的消息队列已存在,但调用进程没有权限访问它

        EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志

        EINVAL:创建共享内存是参数size小于SHMMIN或大于SHMMAX

        ENFILE:已达到系统范围内打开文件总数的限制

        ENOENT:给定的key不存在任何共享内存,并且未指定IPC_CREAT

        ENOMEM:内存不足,无法为共享内存分配内存

shmat():映射

shmat()函数是把共享内存区域对象映射到调用进程的地址空间。

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
/*
shmid:共享内存ID
shmaddr:如果不为NULL,则系统会根据shmaddr来选择一个合适的内存区域;如果为NULL,则系统会自动选择一个合适的虚拟内存空间地址去映射共享内存
shmflg:SHM_RDONLY:以只读方式映射共享内存SHM_REMAP:重新映射,此时shmaddr不能为NULLNULLSHM:自动选择比shmaddr小的最大页对齐地址
返回值:共享内存的起始地址。
*/

共享内存的映射需注意:

共享内存只能以只读或可读写方式映射,无法以只写方式映射。

shmaddr参数一般设置为NULL,让系统自动地寻找合适的地址。当不为NULL时,SHMFLG必须设置为SHM_RND,系统将会选择比shmaddr小而又最大的页对齐地址(即为SHMLBA的整数倍)作为共享内存区域的起始地址。如果没有设置SHM_RND,那么shmaddr必须是严格的页对齐地址。

shmdt():解除映射

shmdt()函数是解除进程和共享内存间的映射。

#include <sys/types.h>
#include <sys/shm.h>
void shmdt(const void *shmaddr);
/*
shmaddr:映射的共享内存的起始地址
返回值:执行成功:0执行失败:-1,并将错误原因存于errno
*/

注意:该函数并不删除所指定的共享内存区,而只是将先前用shmat()函数映射好的共享内存脱离当前进程,共享内存还是存在于物理内存中。

shmctl():获取或设置属性

shmctl()函数用于获取或设置共享内存的相关属性。

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
/*
shmid:共享内存标识符
cmd:IPC_STAT:获取属性信息,放置到 buf 中。IPC_SET:设置属性信息为 buf 指向的内容。IPC_RMID:删除该共享内存。IPC_INFO:获得关于共享内存的系统限制值信息。SHM_INFO:获得系统为共享内存消耗的资源信息。SHM_STAT:与 IPC_STAT 具有相同的功能,但 shmid 为该 SHM 在内核中记录所有 SHM 信息的数组的下标,因此通过迭代所有的下标可以获得系统中所有 SHM 的相关信息。SHM_LOCK:禁止系统将该 SHM 交换至 swap 分区。SHM_UNLOCK:允许系统将该 SHM 交换至 swap 分区。
buf:共享内存属性信息结构体指针,设置或者获取信息都通过该结构体
*/

一个SHM被交换至swap分区后如果被设置了SHM_LOCK,那么任何访问这个SHM的进程都将会遇到页错误。进程可以通过IPC_STAT后得到的mode来检测SHM_LOCKED信息。

struct shmid_ds {struct ipc_perm shm_perm;     /* 所有权和权限 */size_t shm_segsz;             /* 共享内存尺寸(字节) */time_t shm_atime;             /* 最后一次映射时间 */time_t shm_dtime;             /* 最后一个解除映射时间 */time_t shm_ctime;             /* 最后一次状态修改时间 */pid_t shm_cpid;               /* 创建者 PID */pid_t shm_lpid;               /* 后一次映射或解除映射者 PID */shmatt_t shm_nattch;          /* 映射该 SHM 的进程个数 */...
};struct ipc_perm {key_t __key;           /* 该共享内存的键值 key */uid_t uid;             /* 所有者的有效 UID */gid_t gid;             /* 所有者的有效 GID */uid_t cuid;            /* 创建者的有效 UID */gid_t cgid;            /* 创建者的有效 GID */unsigned short mode;   /* 读写权限 + SHM_DEST + SHM_LOCKED 标记 */unsigned short __seq;  /* 序列号 */
};

sem.h文件

#ifndef __SEM_H
#define __SEM_H#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>int init_sem(int sem_id, int init_value);
int del_sem(int sem_id);
int sem_p(int sem_id);
int sem_v(int sem_id);#endif

sem.c文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>union semun
{int val;                //供semctl()函数cmd = SETVAL时使用struct semid_ds *buf;   //供semctl()汉斯cmd = IPC_STAT|IPC_SET时使用
};/* 初始化信号量 */
int init_sem(int sem_id, int init_value)
{union semun sem_union;sem_union.val = init_value;/* 信号量ID,信号量编号,命令,联合体 */if( semctl( sem_id, 0, SETVAL, sem_union) == -1 ){printf("Initialize semaphore error!\n");return -1;}else{printf("Initialize semaphore!\n");}
}/* 删除信号量 */
int del_sem(int sem_id)
{union semun sem_union;/* 信号量ID,信号量编号,命令,联合体 */if( semctl( sem_id, 0, IPC_RMID, sem_union) == -1 ){printf("Delete semaphore error!\n");return -1;}else{printf("Delete semaphore!\n");}
}/* p操作 */
int sem_p(int sem_id)
{struct sembuf sops;sops.sem_num = 0;               //信号量的编号:0~nsems-1sops.sem_op  = -1;              //表示p操作sops.sem_flg = SEM_UNDO;        //系统自动释放在系统中残留的信号量/* 信号量ID,结构体,信号量数量 */if( semop( sem_id, &sops, 1) == -1 ){perror("p operation error!\n");return -1;}else{printf("p operation successful!\n");return 0;}
}/* v操作 */
int sem_v(int sem_id)
{struct sembuf sops;sops.sem_num = 0;               //信号量的编号:0~nsems-1sops.sem_op  = 1;               //表示v操作sops.sem_flg = SEM_UNDO;        //系统自动释放在系统中残留的信号量/* 信号量ID,结构体,信号量数量 */if( semop( sem_id, &sops, 1) == -1 ){perror("v operation error!\n");return -1;}else{printf("v operation successful!\n");return 0;}
}

shm.c文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "sem.h"int main(int argc, char** argv)
{int sem_id, shm_id;char *addr;pid_t pid;/* 创建信号量:键值,数量,模式 */sem_id = semget((key_t)0x1100, 1, IPC_CREAT|0666);/* 创建共享内存:键值,共享内存大小,模式 */shm_id = shmget((key_t)0x1111, 1024, IPC_CREAT|0666);/* 初始化信号量 */init_sem(sem_id, 0);if( ( pid = fork() ) == -1){perror("rork error!\n");}else if(pid == 0)      //子进程{printf("Child process will wait for some seconds...\n");sleep(3);/* 映射共享内存,映射地址系统自动分配 */if( ( addr = shmat(shm_id, NULL, 0) ) == (void *)-1 ){printf("child shmat error!\n");exit(-1);}memcpy(addr, "hello couvrir", 14);printf("the child process is running...\n");sem_v(sem_id);}else                   //父进程{sem_p(sem_id);printf("the father process is running...\n");/* 映射共享内存,映射地址系统自动分配 */if( ( addr = shmat(shm_id, NULL, 0) ) == (void *)-1 ){printf("father shmat error!\n");exit(-1);}printf("share memory string:%s\n", addr);/*解除共享内存映射*/shmdt(addr);sem_v(sem_id);del_sem(sem_id);}exit(0);
}

Makefile文件

照旧

执行过程

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

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

相关文章

利用向导创建MFC

目录 1、项目的创建&#xff1a; 2、项目的管理 &#xff1a; 3、分析以及生成的项目代码 &#xff1a; &#xff08;1&#xff09;、查看CFrame中的消息映射宏 &#xff08;2&#xff09;、自动生成事件 &#xff08;3&#xff09;、在CFrame中添加对应的鼠标处理函数 …

计算机网络学习笔记(三):数据链路层(待更新)

目录 3.1 基本概念 3.1.1 数据链路和帧 3.1.2 三个基本问题 3.2 类型1&#xff1a;使用点对点信道的数据链路层&#xff08;路由器&#xff09; 3.2.1 点对点协议 PPP&#xff1a;特点 3.2.2 点对点协议 PPP&#xff1a;帧格式 3.2.3 点对点协议 PPP&#xff1a;工作状态 …

华为---PPP协议简介及示例配置

PPP协议简介 PPP是Point-to-Point Protocol的简称&#xff0c;中文翻译为点到点协议。与以太网协议一样,PPP也是一个数据链路层协议。以太网协议定义了以太帧的格式&#xff0c;PPP协议也定义了自己的帧格式&#xff0c;这种格式的帧称为PPP帧。 利用PPP协议建立的二层网络称为…

CSS盒子模型的详细解析

03-盒子模型 作用&#xff1a;布局网页&#xff0c;摆放盒子和内容。 盒子模型-组成 内容区域 – width & height 内边距 – padding&#xff08;出现在内容与盒子边缘之间&#xff09; 边框线 – border 外边距 – margin&#xff08;出现在盒子外面&#xff09; d…

基于Spring boot轻松实现一个多数据源框架

Spring Boot 提供了 Data JPA 的包&#xff0c;允许你使用类似 ORM 的接口连接到 RDMS。它很容易使用和实现&#xff0c;只需要在 pom.xml 中添加一个条目&#xff08;如果使用的是 Maven&#xff0c;Gradle 则是在 build.gradle 文件中&#xff09;。 <dependencies>&l…

VS2022更换背景壁纸逐步图示教程

&#x1f984;个人主页:修修修也 ⚙️操作环境:Visual Studio 2022 目录 一.下载壁纸插件 二.更改自定义壁纸 三.调整壁纸布局 一.下载壁纸插件 因为更改自定义壁纸需要一个插件的辅助,所以我们要先下载一个小插件 首先,打开VS2022,点击"扩展"->"管理扩…

PAM从入门到精通(十三)

接前一篇文章&#xff1a;PAM从入门到精通&#xff08;十二&#xff09; 本文参考&#xff1a; 《The Linux-PAM Application Developers Guide》 先再来重温一下PAM系统架构&#xff1a; ​ 更加形象的形式&#xff1a; ​ 五、主要函数详解 11. pam_open_session 概述&…

C语言求 n 阶勒让德多项式的值

完整代码&#xff1a; // 用递归法求 n 阶勒让德多项式的值 // 递归公式为&#xff1a; // n0,P(n)(x)1 // n1,P(n)(x)x // n>1,P(n)(x)((2*n-1)*x - P(n-1)(x) - (n-1)*P(n-2)(x)) / n #include<stdio.h>double func(int n,int x){if (n0){return 1;}if (n1){return…

Hadoop3教程(十):MapReduce中的InputFormat

文章目录 &#xff08;87&#xff09;切片机制与MapTask并行度决定机制&#xff08;90&#xff09; 切片源码总结&#xff08;91&#xff09;FileInputFormat切片机制&#xff08;92&#xff09;TextInputFormat及其他实现类一览&#xff08;93&#xff09; CombineTextInputFo…

44岁的「老板」想变年轻

作者 | 辰纹 来源 | 洞见新研社 从村办集体企业余杭县红星五金厂起家&#xff0c;到生产贴牌油烟机&#xff0c;再到注册“老板”商标&#xff0c;改制有限公司&#xff0c;老板电器已经走过了44个春秋。 在这44年中&#xff0c;老板电器是首家登陆资本市场的高端厨电企业&am…

uniapp高德地图ios 使用uni.chooseLocation选取位置显示没有搜索到相关数据

uniapp云打包后&#xff0c;高德地图ios选取位置显示“ 对不起&#xff0c;没有搜索到相关数据” 详细问题描述 废话不多说&#xff0c;直接上图 解决方案 1.打开高德地图开发平台 2.重新创建key 3.获取云打包时的ios报名作为安全码 4.使用生成的高德key更改manifest.json里…

IDEA同步代码到Gitee

参考博客 https://gitee.com/jakhyd/risk-operation.git

springBoot 日志

springBoot 日志 整合原理日志格式默认日志格式在配置文件中修改日志格式 在业务中写日志日志级别日志分组文件输出归档和切割归档切割 自定以日志系统切换默认日志场景 log4j2的使用 最佳实战 整合原理 规范&#xff1a;项目开发中不要编写&#xff1a;System.out.printIn()&…

UML软件哪个好?10款好用的UML工具和画图软件推荐!

UML&#xff08;统一建模语言&#xff09;图在处理复杂项目时&#xff0c;如软件开发、系统设计、业务流程分析或系统架构等&#xff0c;能够发挥巨大作用。 UML作为项目的通用蓝图&#xff0c;可以告知团队成员关于需要构建什么&#xff0c;它应该如何运作&#xff0c;以及不…

数据结构和算法(13):优先级队列

概述 按照事先约定的优先级&#xff0c;可以始终高效查找并访问优先级最高数据项的数据结构&#xff0c;也统称作优先级队列 优先级队列将操作对象限定于当前的全局极值者。 根据数据对象之间相对优先级对其进行访问的方式&#xff0c;与此前的访问方式有着本质区别&#xf…

springBoot--web--静态资源规则

规则一&#xff1a; 访问&#xff1a;/webjars/** 路径就去 classpath:/META-INF/resources/webjars/下载资源 a.maven导入依赖 规则二&#xff1a; 访问&#xff1a;/** 路径就去 静态资源默认的四个位置找资源 a. classpath:/META-INF/resources/ b.classpath:/resourc…

【UE5】 ListView使用DataTable数据的蓝图方法

【UE5】 ListView使用DataTable数据的蓝图方法 ListView 是虚幻引擎中的一种用户界面控件&#xff0c;用于显示可滚动的列表。它可以用于显示大量的数据&#xff0c;并提供了各种功能和自定义选项来满足不同的需求。 DataTable是虚幻引擎中的一种数据表格结构&#xff0c;用于存…

Flink学习笔记(三):Flink四种执行图

文章目录 1、Graph 的概念2、Graph 的演变过程2.1、StreamGraph (数据流图)2.2、JobGraph (作业图)2.3、ExecutionGraph (执行图)2.4、Physical Graph (物理图) 1、Graph 的概念 Flink 中的执行图可以分成四层&#xff1a;StreamGraph -> JobGraph -> ExecutionGraph -&g…

1811_spacemacs从v.0.200.13升级到v.0.200.14的几点变化感受

全部学习汇总&#xff1a; GreyZhang/editors_skills: Summary for some common editor skills I used. (github.com) 安装了全新的spacemacs的配置&#xff0c;查看了一下版本是v.0.200.14。在此之前&#xff0c;我使用的版本是v.0.200.13。现在还没有在这个配置上完成我所有的…

[opencv]图像和特征点旋转

本来说这是很简单的一个内容&#xff0c;图像旋转只需要使用opencv中自带的旋转函数即可完成&#xff0c;但是最近在做特征点旋转的时候发现使用内置rotate函数给图像旋转90度&#xff0c;再用getRotationMatrix2D得出的旋转矩阵对特征点旋转&#xff0c;画出来的特征点位置全部…