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

嵌入式学习笔记--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://www.xdnf.cn/news/20358.html

相关文章:

  • 区块链技术
  • 如何减少微型导轨表面破损情况?
  • JWT概念及使用详解
  • Dart语言基础 关键字 var与dynamic
  • 整车无线布置的综述
  • 【完整源码+数据集+部署教程】室内场景分割系统源码和数据集:改进yolo11-DWR
  • 算法题(200):最大子段和(动态规划)
  • 责任链框架 03:处理器实现
  • 《Science》神经炎症综述思路套用:从机制到跨领域研究范式
  • Python实现生成矩形框、三角形框、六边形框和圆环点云
  • 自动拆箱和装箱的原理与作用
  • HMI(人机界面)
  • 【基础-单选】UIAbility实例创建完成时触发的回调
  • HTML 列表类型
  • 5-8单元格区域与VS数组应用(实例:提取满足条件的数据)
  • Qt多线程编程学习
  • EG2103 SOP-8 内置600V功率MOS管 栅极驱动芯片
  • I/O 多路复用 (I/O Multiplexing)
  • 四个关于云属性的四个卫星数据集的介绍
  • 基于Spring Boot + Vue3的办公用品申领管理系统
  • 部署AIRI
  • lesson55:CSS导航组件全攻略:从基础导航条到动态三级菜单与伸缩菜单实现
  • 02.继承MonoBehaviour的单例模式基类
  • Python快速入门专业版(七):整数与浮点数:Python数值类型的运算与精度问题(附解决方案)
  • 项目中的一些比较实用的自定义控件
  • Python文件打包为EXE的工具v1.0
  • 《AI大模型应知应会100篇》第67篇 Web应用与大模型集成开发实践——1小时打造国产大模型智能客服系统
  • MySQL问题5
  • github上传步骤
  • 季度最强策略:年化247%,回撤10%,夏普比率3.79。附大小盘轮动策略python源代码。