进程间通信之共享内存

这篇具有很好参考价值的文章主要介绍了进程间通信之共享内存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

进程间通信之共享内存

1.1共享内存的介绍

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

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

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

进程间通信之共享内存

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

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

进程间通信之共享内存

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

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

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

进程间通信之共享内存

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

进程间通信之共享内存

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

进程间通信之共享内存

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

    进程间通信之共享内存

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()来访问管道文件的,这样就有数据在缓冲区之间的拷贝操作,进而使得效率变低

进程间通信之共享内存

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

学习过管道我们知道管道是自带同步与互斥机制的,读写是不可以同时进行的。但是共享内存就不带这种机制,这就使得其数据的读写可以是同时进行的,要想实现类似同步与互斥的机制就需要用到锁或则信号量来解决文章来源地址https://www.toymoban.com/news/detail-469581.html

到了这里,关于进程间通信之共享内存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux 共享内存mmap,进程通信

    进程间通信是操作系统中重要的概念之一,使得不同的进程可以相互交换数据和进行协作。其中,共享内存是一种高效的进程间通信机制,而内存映射(mmap)是实现共享内存的一种常见方法。 存储映射 I/O 是 一个磁盘文件 与 存储空间中的一个缓冲区相映射 。于是, 当从缓

    2024年02月13日
    浏览(42)
  • 【Linux】进程间通信——管道/共享内存

    进程间通信( Inter-Process Communication,简称IPC )是指不同进程之间进行数据交换和共享信息的机制和技术。在操作系统中,每个进程都是独立运行的,有自己的地址空间和数据,因此进程之间需要一种机制来进行通信,以便彼此协调工作、共享数据或者进行同步操作。 进程间

    2024年02月16日
    浏览(40)
  • 进程间通信--共享内存详解【Linux】

    本文详细讲解了共享内存的原理和使用,并且通过实例代码角度来深度理解共享内存,下面就让我们开始吧。 数据传输:一个进程需要将它的数据发送给另一个进程 资源共享:多个进程之间共享同样的资源。 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(

    2024年02月02日
    浏览(39)
  • 【Linux】进程间通信之共享内存

    共享内存比管道快哦~ 文章目录 前言 一、共享内存的实现原理 二、实现共享内存的代码 总结 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的

    2024年02月03日
    浏览(45)
  • C++ Windows进程间共享内存通信

    在项目工程中需要64位程序调用32位程序并加以通信。 实现了两个进程间的内存共享。 提示:以下是本篇文章正文内容,下面案例可供参考 1、进程间通信原理: 主要实现: • 系统使用内存映射文件,以便加载和执行. exe和DLL文件。这可以大大节省页文件空间和应用程序启动

    2024年02月03日
    浏览(43)
  • Linux--进程间的通信-共享内存

    前文: Linux–进程间的通信-匿名管道 Linux–进程间的通信–进程池 Linux–进程间的通信-命名管道 对于两个进程,通过在内存开辟一块空间(操作系统开辟的),进程的虚拟地址通过页表映射到对应的共享内存空间中,进而实现通信 ; 特点和作用: 高效性: 共享内存是一种

    2024年04月26日
    浏览(38)
  • 【hello Linux】进程间通信——共享内存

    目录 前言: 1. System V共享内存 1. 共享内存的理解 2. 共享内存的使用步骤 3. 共享内存的使用         1. 共享内存的创建         查看共享内存         2. 共享内存的释放         3. 共享内存的挂接         4. 共享内存的去挂接 4. 共享内存的使用示例 1. 两进

    2024年02月01日
    浏览(91)
  • C# .Net 多进程同步 通信 共享内存

    节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。         内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当。实际上,任何想要共享数据的通信模型都会在幕后使用它。   

    2024年02月06日
    浏览(43)
  • 【Linux】进程间的通信之共享内存

    利用 内存共享 进行进程间的通信的原理其实分为以下几个步骤: 在物理内存中创建一块共享内存。 将共享内存链接到要通信的进程的页表中,并通过页表进行进程地址空间的映射。 进程地址空间映射完毕以后返回首个虚拟地址,以便于进程之间进行通信。 根据共享内存的

    2024年02月09日
    浏览(45)
  • 【Linux】进程间通信——system V共享内存

    目录  写在前面的话 System V共享内存原理 System V共享内存的建立 代码实现System V共享内存 创建共享内存shmget() ftok() 删除共享内存shmctl() 挂接共享内存shmat() 取消挂接共享内存shmdt() 整体通信流程的实现          上一章我们讲了进程间通信的第一种方式 --- 管道,这一章我

    2024年02月14日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包