当前位置: 首页 > news >正文

嵌入式学习笔记--Linux系统编程阶段--DAY07进程间通信--存储映射和共享内存

1.存储映射

存储映射 I/O (Memory-mapped I/O) 使一个磁盘文件存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区则相应的字节就自动写入文件。这样,就可在不适用 read 和 write 函数的情况下,使用地址(指针)完成 I/O 操作。 使用存储映射这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap 函数来实现。
     这个文件仅仅是用来进程间通信的桥梁。

1.1mmap函数映射

mmap函数:建立映射区

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
参数解释
addr 地址,填 NULL(让系统自己找一个合理的地址
length 长度 要申请的映射区的长度
prot 权限(读还是写)
        PROT_READ 可读
        PROT_WRITE 可写
flags 标志位
        MAP_SHARED 共享的 -- 对映射区的修改会影响源文件(一般是这个)
        MAP_PRIVATE 私有的
fd 文件描述符 需要打开一个文件
offset 指定一个偏移位置 ,从该位置开始映射(一般写0,不偏移)
返回值
        成功 返回映射区的首地址
        失败 返回 MAP_FAILED ((void *) -1)

1.2munmap函数

munmap函数:解除映射(断开当前进程和磁盘文件的映射关系,不影响其他进程的映射)

int munmap(void *addr, size_t length);
参数解释
        addr 映射区的首地址
        length 映射区的长度
返回值
        成功 返回 0
        失败 返回 -1

1.3truncate函数

truncate函数:拓展文件的大小
一般磁盘映射是新建一个文件,这个文件新建的时候,大小是0,因此里面无法存储数据,所以需要拓展文件的大小
int truncate(const char *path, off_t length);
参数解释
        path 要拓展的文件
        length 要拓展的长度

1.4代码案例

不相关的进程间通信

写代码:

#define _POSIX_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
#include <sys/mman.h>int main(int argc, char const *argv[])
{//1.通过open打开文件int fd = open("temp",O_RDWR |O_CREAT,0666);//新建的文件无大小//2.拓展文件的大小truncate("temp",16);//3.建立映射char *buff = (char *)mmap(NULL,16,PROT_READ | PROT_WRITE,MAP_SHARED ,fd,0);//4.使用内存区域strcpy(buff,"hello mmap");//5.断开映射munmap(buff,16);close(fd);return 0;
}

读代码:

#define _POSIX_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, char const *argv[])
{//1.通过open打开文件int fd = open("temp",O_RDWR |O_CREAT,0666);//新建的文件无大小//2.拓展文件的大小truncate("temp",16);//3.建立映射char *buff = (char *)mmap(NULL,16,PROT_READ | PROT_WRITE,MAP_SHARED ,fd,0);//4.使用内存区域printf("收到数据%s\n",buff);printf("收到数据%s\n",buff);//5.断开映射munmap(buff,16);close(fd);return 0;
}

除非被覆盖,否则数据一直在

2.共享内存

2.1共享内存理论

共享内存允许两个或者多个进程共享给定的存储区域。(进程间通信的最快的方式)

共享内存的特点

1、 共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了数据, 共享这个内存区域的所有进程就可以立刻看到其中的内容。

2、 使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥若一个进程正在向共享内存区写数据, 则在它做完这一步操作前, 别的进程不应当去读、 写这些数据

在 ubuntu 部分版本中共享内存限制值如下 共享存储区的最小字节数:

1 共享存储区的最大字节数: 32M

共享存储区的最大个数: 4096

每个进程最多能映射的共享存储区的个数: 4096

2.2共享内存的API

shmget函数:创建或打开一块共享内存区,即获得一个共享内存标识符

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size,int shmflg);
功能:
        创建或打开一块共享内存区
参数:
        key:IPC 键值(需要ftok函数)
        size:该共享存储段的长度(字节)
        shmflg:标识函数的行为及共享内存的权限。
                参数:shmflg:
                        IPC_CREAT:如果不存在就创建
                        IPC_EXCL:如果已经存在则返回失败
                        位或权限位:共享内存位或权限位后可以设置共享内存的访问权限,格式 和 open 函数的 mode_t 一样,但可执行权限未使用
返回值:
        成功:返回共享内存标识符。
        失败:返回-1

使用 shell 命令操作共享内存

查看共享内存

ipcs -m --内存

ipcs -q --队列

ipcrm -m shmid --删除shmid的共享内存

代码案例:

创建一个共享内存,获取标识符:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main(int argc, char const *argv[])
{ // 1.获取唯一key值key_t key = ftok("/home/qf/桌面", 2504);// 2.得到唯一共享内存标识(分配物理内存)int shm_id = shmget(key,16,IPC_CREAT | 0666) ;  printf("%d\n",shm_id);return 0;
}

shmat函数:将一个共享内存段映射到调用进程的数据段中,即建立进程与物理内存的映射

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr,int shmflg);
函数功能:
        将一个共享内存段映射到调用进程的数据段中。
参数:
        shmid:共享内存标识符。
        shmaddr:共享内存映射地址(若为 NULL 则由系 统自动指 定),推荐使用 NULL
        shmflg:共享内存段的访问权限和映射条件(映射时的读写关系)
                0:共享内存具有可读可写权限。
                SHM_RDONLY:只读。
                SHM_RND:(shmaddr 非空时才有效)(自己申请的虚拟地址来进行映射(例如malloc来的),建议shmaddr选NUMM)
                没有指定 SHM_RND 则此段连接到 shmaddr 所指定的地址上(shmaddr 必需 页对齐)。 指定了 SHM_RND 则此段连接到 shmaddr- shmaddr%SHMLBA 所表示的地址 上。
返回值:
成功:返回共享内存段映射地址
失败:返回 -1
代码案例:建立内存与进程间的映射
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main(int argc, char const *argv[])
{ // 1.获取唯一key值key_t key = ftok("/home/qf/桌面", 2504);// 2.得到唯一共享内存标识(分配物理内存)int shm_id = shmget(key,16,IPC_CREAT | 0666) ;  printf("%d\n",shm_id);//3.建立进程和物理内存间的映射char *p = (char *)shmat(shm_id,NULL,0);//4.断开映射,只断开自己return 0;
}

shmdt函数:将共享内存和当前进程分离(仅仅是断开联系并不删除共享内存)

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:
        将共享内存和当前进程分离(仅仅是断开联系并不删除共享内存)
参数:
        shmaddr:共享内存映射地址。
返回值:
成功返回 0
失败返回 -1

shmctl:共享内存控制函数

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd,struct shmid_ds *buf);
功能:
        共享内存空间的控制。
参数:
        shmid:共享内存标识符。
        cmd:函数功能的控制。
        buf:shmid_ds 数据类型的地址,用来存放或修改共享内存的属性。
                cmd:函数功能的控制
                        IPC_RMID:删除。
                        IPC_SET:设置 shmid_ds 参数。
                        IPC_STAT:保存 shmid_ds 参数。
                        SHM_LOCK:锁定共享内存段(超级用户)
                        SHM_UNLOCK:解锁共享内存段。
返回值:
成功返回 0
失败返回 -1
注意:
SHM_LOCK 用于锁定内存,禁止内存交换。并不代表共享内存被锁定后,禁止其它进程访问。其真正的意义是:被锁定的内存不允许被交换到虚拟内存中(即只针对当前进程)。这样做的优势在于让共享内存一直处于内存中,从而提高程序性能

读写代码案例:

写:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main(int argc, char const *argv[])
{ // 1.获取唯一key值key_t key = ftok("/home/qf/桌面", 2504);// 2.得到唯一共享内存标识(分配物理内存)int shm_id = shmget(key,16,IPC_CREAT | 0666) ;  printf("%d\n",shm_id);//3.建立进程和物理内存间的映射char *p = (char *)shmat(shm_id,NULL,0);strcpy(p,"hello world!");//4.断开映射,只断开自己shmdt(p);return 0;
}

读:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>int main(int argc, char const *argv[])
{ // 1.获取唯一key值key_t key = ftok("/home/qf/桌面", 2504);// 2.得到唯一共享内存标识(分配物理内存)int shm_id = shmget(key,16,IPC_CREAT | 0666) ;  printf("%d\n",shm_id);//3.建立进程和物理内存间的映射char *p = (char *)shmat(shm_id,NULL,SHM_RDONLY);printf("收到数据:%s\n",p);//4.断开映射,只断开自己return 0;
}


文章转载自:

http://V4IRTfxS.mfxcg.cn
http://zFfttSHD.mfxcg.cn
http://M36RBW5K.mfxcg.cn
http://FWDD6vKG.mfxcg.cn
http://3opH3TUg.mfxcg.cn
http://Zh6xDMV4.mfxcg.cn
http://SFyzHUNv.mfxcg.cn
http://BeP1ch3q.mfxcg.cn
http://GJ4Evq7E.mfxcg.cn
http://3dMICRrv.mfxcg.cn
http://nGjTD2RU.mfxcg.cn
http://S1JS2vSz.mfxcg.cn
http://Lz2oEJlB.mfxcg.cn
http://LzE7ArD2.mfxcg.cn
http://4XG7eRkI.mfxcg.cn
http://KDcVgTKe.mfxcg.cn
http://sp7WTBT4.mfxcg.cn
http://p0t5KxZk.mfxcg.cn
http://FhSedsrJ.mfxcg.cn
http://Seob7GY4.mfxcg.cn
http://lsRW4vOa.mfxcg.cn
http://4dKxtnUL.mfxcg.cn
http://QQoq84hR.mfxcg.cn
http://os0XzgI3.mfxcg.cn
http://RvjV5MMh.mfxcg.cn
http://cMu8kOHU.mfxcg.cn
http://fxUuOkQb.mfxcg.cn
http://bck9UtZC.mfxcg.cn
http://OHf5qh22.mfxcg.cn
http://tMvqMDwv.mfxcg.cn
http://www.dtcms.com/a/371128.html

相关文章:

  • DMA寄存器学习
  • 对于单链表相关经典算法题:206. 反转链表及876. 链表的中间结点的解析
  • 云原生部署_k8s入门
  • 分布式数据库的历史演变与核心原理
  • 线代:排列与逆序
  • GPIO的配置中开漏输出与推挽输出的差别
  • 有有有深度学习
  • 车载通信架构 --- DoIP企业规范中细节有哪些?
  • 【Linux基础】Linux系统管理:GPT分区实践详细操作指南
  • 6-2-4 解决第一次发送失败
  • 跨域彻底讲透
  • c++之基础B(x转10进制,含十六进制)(第四课)
  • 自注意力机制解析
  • 数据结构——队列(Java)
  • Dify 从入门到精通(第 79/100 篇):Dify 的多模态模型评估(高级篇)
  • 具身导航“所想即所见”!VISTA:基于生成式视觉想象的视觉语言导航
  • synchronized 锁升级
  • 深入解析 Java 的类加载机制
  • GEE:时间序列合成一个不填补空洞,保留时间序列空像素的新影像
  • Zoom AI 技术架构研究:联合式方法与多模态集成
  • Arch Linux运维自动更新脚本推荐
  • 深度拆解OpenHarmony NFC服务:从开关到卡模拟掌握近场通信技术
  • 第5章递归:分治法
  • 【Python字符串格式化】:全面指南与最佳实践
  • MySQL学习记录-索引
  • C++进阶——继承(2)
  • Oracle体系结构-Redo Log Buffer详解
  • 【医学影像 AI】YoloCurvSeg:仅需标注一个带噪骨架即可实现血管状曲线结构分割
  • Nginx安装及版本迭代热部署详解
  • [光学原理与应用-422]:非线性光学 - 计算机中的线性与非线性运算