IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 进程间通信之共享内存 -> 正文阅读

[数据结构与算法]进程间通信之共享内存

进程间通信之共享内存

1.1共享内存的介绍

共享内存是最快的进程间通信形式,是通过调用系统接口(shmget)由操作系统开辟一块物理内存,然后通过页表映射到进程地址空间中,进而使得用户可以使用这块内存,两个进程间共用一块共享内存通过数据交互就可以建立通信。

1.2建立共享内存前后虚拟内存和物理内存之间的示意图

未创建共享内存之前的虚拟内存和物理内存之间的联系

在这里插入图片描述

  • 虚拟地址和物理内存之间是通过页表建立联系的,我们看到的都是物理内存映射到页表上的虚拟内存而不是真实的物理内存,
  • 其中task_struct 是进程的数据结构(通过该数据结构来描述 管理该数据结构就是对进程的管理) mm_struct 是进程地址空间的数据结构

创建共享内存之后的虚拟内存和物理内存之间的联系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5X339Qj-1656584415666)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629224323893.png)]

  • 创建了共享内存后,将两个进程的物理地址都指向该块物理内存后就可以使得两个进程看到同一份资源,从而实现信息的交互,实现通信

2.1通过共享内存进行通信的具体步骤介绍

  • 1、申请共享内存 通过函数shmget()创建(申请)出共享内存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hdtuovKM-1656584415668)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629225840008.png)]

  • 2、将共享内存挂接到进程地址空间 通过函数shmat() 将进程的和该共享内存进行挂接;实质上就是进程开辟新的虚拟地址空间,通过修改页表,取消原来的虚拟内存和物理内存的映射关系,将共享内存(这块物理内存)与进程的虚拟内存建立映射关系,使得进程可以使用共享内存

在这里插入图片描述

  • 3、去关联共享内存 通过函数 shmdt() 去关联共享内存;修改页表,取消共享内存与虚拟内存之间的映射关系,恢复进程原来的物理内存和虚拟内存之间的映射关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiDzFixX-1656584415671)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629234723251.png)]

  • 4、释放共享内存 通过函数int shmctl(int shmid, int cmd, struct shmid_ds *buf);释放共享内存 ;共享内存的生命周期是随着内核的而不是随着进程的结束而自动释放的(不同于文件),如果使用完不释放就会使得内存越来越少,造成内存泄漏,故申请的共享内存使用完后要记得释放

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AGPCMcJS-1656584415672)(C:\Users\华哥\AppData\Roaming\Typora\typora-user-images\image-20220629234820210.png)]

2.2共享内存查看和删除的指令

2.2.1查看共享内存

//输入指令
ipcs -m 

2.2.2删除共享内存

//输入指令
ipcrm -m +[shmid]//shmid是共享内存id(用户)

3.1两个进程通过同一块共享内存进行通信简单演示

  • 两个进程公用一块共享内存,然后直接对该内存操作,就像mallocc出来的空间一样使用,不用调用系统接口read write之类的来访问这块内存。
    在这里插入图片描述

具体的代码:

//头文件 包含用ftok()创建的key 需要的参数Pathname和proj_id
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#define pathname "/home/zh/nodeput/lesson23"
#define proj_id 0x36
#define SIZE 4096
-------------------------------------------
//client.c
#include"serve.h"
int main()
{
  key_t key=ftok(pathname,proj_id);
  if(key<0)
  {
    perror("ftok");
  }

  int shmid=shmget(key,SIZE,IPC_CREAT);//创建
  char* mem=(char*)shmat(shmid,NULL,0);//挂接

  //开始通信
  
  int i=0;
  while(1)
  {
    mem[i] = 'A'+ i;//这里是直接对开辟出来的共享内存进行使用 对其进行赋值操作  然后可以让另一个进程打印出来
    i++;
    mem[i]='\0';
    sleep(1);
  }
  shmdt(mem);//去关联 
  shmctl(shmid,IPC_RMID,NULL);//释放
  return 0;
}
-------------------------
//serve.c

#include"serve.h"
int main()
{
  key_t key=ftok(pathname,proj_id);//生成key
  if(key<0)
  {
    perror("ftok");
    return 1;
  }
  int shmid= shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0644);//通过key创建出共享内存
  if(shmid<0)
  {
    perror("shmget");
    return 2;
  }
  char* mem=(char*)shmat(shmid,NULL,0);//挂接共享内存

  //开始通信
  while(1)
  {
    printf("client sent: %s\n",mem);
    sleep(1);
  }
  shmdt(mem);//去关联共享内存
  shmctl(shmid,IPC_RMID,NULL);//释放共享内存
  return 0;
}

3.1.1需要注意的几个点:

  • 1、*key_t ftok(const char pathname,int proj_id)**函数的第一个参数是一个必须存在的路径,可以是文件也可以是目录
  • 2、该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关
  • 3、proj_id是可以根据自己的约定,随意设置。这个数字,有的称之为project ID 在UNIX系统上,它的取值是1到255,8个比特位,2个字节

3.1.2几个函数的参数返回值的介绍

1.创建共享内存函数

int shmget(key_t key,size_t size,int shmflg)

  • 第一个参数:key key 是通过ftok()函数根据pathname和proj_id创建出来的具有唯一映射关系的一个值,帮助操作系统用来标识一块共享内存

  • 第二个参数:size size是我们要创建的共享内存的大小,我们看到的内存实际上是虚拟内存,是物理内存通过页表映射出来的,总是提到映射,可计算机到底是怎样将虚拟地址空间映射到实实在在的物理内存上的呢?这就要提到内存分段和分页模式了 这个转换过程有操作系统和CPU共同完成. 操作系统为CPU设置好页表 CPU通过MMU单元进行地址转换 简单的说,就是人为的把线性地址空间划分为一个一个4k的(几乎所有的PC上的操作都使用4KB大小的页)逻辑页,把内存页以同样的方法等分为固定大小的物理页 4kb,4096字节,为了更好的使用内存size最好是对齐4096 也就是说最好设置成4096的整数倍

  • 第三个参数 :shmflg 主要是和一些标志有关,包括IPC_CEREAT和IPC_EXCL,这两个与open()的O_CREAT和O_EXCL类似。

    • 使用说明:
    • 1、如果是IPC_CREAT单独使用就是如果该函数对应key的共享内存不存在就创建并且返回该该块共享内存的shmid 如果该块共享内存已经存在了就直接返回其对应的shmid IPC_CREAT单独使用shmget()函数调用一定会成功,要么返回的是已经存在的共享内存的shmid要么是返回新创建的共享内存的shmid
    • 2、如果是IPC_CREAT和IPC_EXCL 配合使用就是当且仅当该块共享内存不存在时才会创建并且返回其对应的神shmid,否则就会返回-1
    • 3、IPC_EXCL标志单独使用并没有太大的意义 只有和IPC_CREAT配合使用才能发挥其作用,可以保证成功创建的共享内存必定是新创建的,而不是已存在的。
    • 4、对于用户的读取和写入许可指定SHM_R和SHM_W(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,(SHM_R>6)和(SHM_W>6)是全局读取和写入许可

2.挂接共享内存函数

**void shmat(int shmid, const void shmaddr, int shmflg);

  • 第一个参数:shmid 就是shmget创建好的共享内存的shmid(一个整数标识符),可以通过这个标识符释放掉对应的共享内存
  • 第二个参数:shmaddr 是指定挂接到的地址,如果为NULL则由操作系统自动选择一个合适的地址;如果不为空且没有指定SHM_RND,则此段链接到shmaddr所指定的地址上,如果shmaddr非空并且指定了SHM_RND则此段连接到shmaddr -(shmaddr mod SHMLAB)所表示的地址上.SHM_RND命令的意思是取整,SHMLAB的意思是低边界地址的倍数,它总是2的乘方。该算式是将地址向下取最近一个 SHMLAB的倍数。除非只计划在一种硬件上运行应用程序(这在当今是不大可能的),否则不用指定共享段所连接到的地址。所以一般应指定shmaddr为0,以便由内核选择地址
  • 第三个参数:shmflg如果是0 就是读写模式,SHM_RD0NLY就是只读模式

3.去关联共享内存函数

**void shmat(int shmid, const void shmaddr, int shmflg)

  • 第一个参数:shmid 就是shmget创建好的共享内存的shmid(一个整数标识符),可以通过这个标识符释放掉对应的共享内存
  • 第二个参数和第三个参数和上面的shmat()相同

4.释放共享内存函数

*int shmctl(int shmid, int cmd, struct shmid_ds buf)

  • 第一个参数:共享内存的标识符
  • 第二个参数:操作命令 有IPC_STAT、IPC_SET、IPC_RMID
    • IPC_STAT是查看共享内存的状态,把共享内存的shmid_ds结构复制到buf中
    • IPC_SET是改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid结构内
    • IPC_RMID是释放这块共享内存
  • 第三个参数:buf 共享内存的管理结构,结构体类型
  • 返回值:成功0 出错-1

4.1共享内存通信和管道通信的比较

1.共享内存通信拷贝数据次数少,速度快

  • 共享内存是创建好后就可以直接使用的,就像malloc 开辟的空间一样,不需要再另外调用函数来访问这块内存

  • 而管道通信的时候创建好管道后需要调用系统接口read()和write()来访问管道文件的,这样就有数据在缓冲区之间的拷贝操作,进而使得效率变低

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdMBg9KY-1656584415675)(1.1共享内存的介绍/image-20220630181015039.png)]

2.管道自带同步与互斥机制,而共享内存没有

学习过管道我们知道管道是自带同步与互斥机制的,读写是不可以同时进行的。但是共享内存就不带这种机制,这就使得其数据的读写可以是同时进行的,要想实现类似同步与互斥的机制就需要用到锁或则信号量来解决

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 11:03:35  更:2022-07-03 11:05:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:42:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码