文章目录

  • 共享内存
    • 共享内存特点
    • 共享内存原理图
    • 共享内存管理数据结构:
    • 函数原型
      • 创建系统层面唯一性标ipc ftok 函数:
      • 创建共享内存函数shmget()
      • 获得共享内存地址函数shmat()
      • 删除共享内存函数shmdt()
      • 共享内存控制函数shmctl()
    • 共享内存流程:
    • 共享内存例子
      • Server.c
      • Client.c
      • Makefile
      • 运行截图

共享内存

​ 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,它是在多个进程之间对内存段进行映射的方式实现内存共享的。这是IPC最快捷的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则是需要将数据通过中间机制进行转换;与此相反,共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅是地址不同而已,因此不需要进行复制,可以直接使用此段空间。

共享内存特点

进程间数据交换的实现方式包括三类

1、通过文件,比如命名管道文件,相互通信的进程通过访问同一磁盘文件实现数据交换。存在read、write等系统调用,效率低下,速度慢、

2、通过内核,比如消息队列,需要进行用户、内核的内存拷贝,开销大,效率低、速度慢

3、通过共享内存,读写速度快,无需数据拷贝、系统调用等,效率高

1、共享内存为相互的通信的进程提供了同一块物理内存空间,每个进程都可以直接访问,不需要用户内核之间的数据拷贝或者系统调用,大大提高了通信的速度,是最快的进程间通信方式
2、共享内存并未提供同步机制,多进程竞争同个共享资源会造成数据混乱
3、共享内存生命周期是随内核的,不是随进程的,程序员必须释放。

共享内存原理图

​ 每个进程都有独立的虚拟空间地址,通过MMU地址转换将虚拟地址与物理地址进行映射,每个进程虚拟地址空间都会映射到不同的物理地址,每个进程在物理内存空间都是相互独立和隔离的。共享内存通过分配一块共享的物理空间,将其挂接到相互通信息的进程虚拟地址空间中,实现虚拟地址到共享物理内存的映射。

共享内存管理数据结构:

结构shmid_ds结构定义如下:

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; /*最后调用函数 shmat ()/shmdt ()*/shmatt_t shm_nattch; /*现在挂接的数量*/
}

函数原型

​ system V提供的IPC机制包括消息队列,信号量和共享内存3种。使用IPC前必须先创建,每种IPC都有特定的生产者、所有者和访问权限。

​ pcs命令可以查看当前系统正在使用的IPC工具。一个IPC工具至少包含key值、ID值、拥有者、权限和使用的大小等关键信息。如果需要手工删除某个IPC机制,可以使用ipcrm命令。

创建系统层面唯一性标ipc ftok 函数:
//获取IPC键值 用于区分不同的ipc
//key_t key 用来进行进程间通信的,让不同进程能看到同一份资源
key_t ftok(const char *pathname, int proj_id);

参数 pathname:为文件路径,或目录,一般是当前目录。
参数 id:为一个整形变量,是子序号,参与构成ftok()函数的返回值。虽然是int类型,但是只使用8bits(1-255)。
在ftok()函数创建key值过程中使用了该文件属性的st_dev 和st_ino。
key值构成:
key值的第31-24(共8位)为ftok()第二个参数的低8位。//第二个参数的用处在这里。
key值的第23-16(共8位)为该文件的st_dev属性的第8位。
key值的第15-0为该文件的st_ino属性的低16位。

创建共享内存函数shmget()

函数shmget()用于创建一个新的共享内存段,或者访问一个现有的共享内存段,它与消息队列以及信号量集合对应的函数十分相似。函数shmget()的原型如下:

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
/*执行成功返回值为shmid 共享内存的标识符ID
key:只是用来在系统层面进行标识唯一性的,不能用来管理shm。
shmid:是OS给用户返回的ID,用来在用户层进行shm的管理。
*/

shmget()的第一个参数是关键字的值。然后,这个值将与内核中现有的其他共享内存段的关键字值相比较。在比较之后,打开和访问操作都将依赖于shmflg参数的内容。size参数为共享内存大小,一般为存物理页的整数倍。

IPC_CREAT:如果在内核中不存在该内存段,则创建它。

IPC_EXCL:当与IPC_CREAT一起使用时,如果该内存段早已存在,则此次调用将失败。

如果只使用IPC_CREAT, shmget()或者将返回新创建的内存段的段标识符,或者返回早已存在于内核中的具有相同关键字值的内存段的标识符。如果同时使用IPC_CREAT和IPC_EXCL,则可能会有两种结果:如果该内存段不存在,则将创建一个新的内存段;如果内存段早已存在,则此次调用失败,并将返回-1。IPC_EXCL本身是没有什么用处的,但在与IPC_CREAT组合使用时,它可用于防止一个现有的内存段为了访问而打开着。旦进程获得了给定内存段的合法IPC标识符,它的下一步操作就是连接该内存段,或者把该内存段映射到自己的寻址空间中。

获得共享内存地址函数shmat()

函数shmat()用来获取共享内存的地址,获取共享内存成功后,可以像使用通用内存一样对其进行读写操作。函数的原型如下:

#include <sys/types.h>
#include <sys/shm.h>
void *shmat (int shmid, const void *shmaddr, int shmflg);
/*返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1*/

如果shmaddr参数值等于0,则内核将试着查找一个未映射的区域。用户可以指定一个地址,但通常该地址只用于访问所拥有的硬件,或者解决与其他应用程序的冲突。

SHM_RND标志可以与标志参数进行OR操作,结果再置为标志参数,这样可以让传送的地址页对齐(舍入到最相近的页面大小)。此外,如果把SHM_RDONLY标志与标志参数进行OR操作,结果再置为标志参数,这样映射的共享内存段只能标记为只读方式。当申请成功时,对内存的操作与一般内存一样,可以直接进行写入和读出,以及偏移的操作。

IPC_REMAP:替换位于shmaddr处的任意既有映射:共享内存段或内存映射

删除共享内存函数shmdt()

函数shmdt()用于删除一段共享内存。函数的原型如下:

#include <sys/types.h>
#include <sys/shm.h>
int shmdt (const void *shmaddr);

当某进程不再需要一个共享内存段时,它必须调用这个函数来断开与该内存段的连接。这与从内核删除内存段是两回事!在成功完成了断开连接操作以后,相关的shmid_ds结构的shm_nattch成员的值将减去1。如果这个值减到0,则内核将真正删除该内存段。

共享内存控制函数shmctl()

共享内存的控制函数shmctl()的使用类似ioctl)的方式对共享内存进行操作:向共享内存的句柄发送命令,来完成某种功能。函数shmctl()的原型如下,其中shmid是共享内存的句柄,cmd是向共享内存发送的命令,最后一个参数buf则是向共享内存发送命令的参数。

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl (int shmid, int cmd, struct shmid_ds *buf);

此函数与消息队列的msgctlO调用是完全类似的,它的合法命令值是:

IPC_STT:获取内存段的shmid_ds结构,并把它存储在buf参数所指定的地址中。

IPC_SET 设置内存段shmid_ds结构的ipc_perm成员的值,此命令是从buf参数中获得该值的。

IPC_RMID:标记某内存段,以备删除。该命令并不真正地把内存段从内存中删除。相反,它只是标记上该内存段,以备将来删除。只有当前连接到该内存段的最后一个进程正确地断开了与它的连接,实际的删除操作才会发生。当然,如果当前没有进程与该内存段相连接,则删除将立刻发生。为了正确地断开与其共享内存段的连接,进程需要调用 shmdt()函数。

共享内存流程:

1、创建ipc系统唯一标识key -> ftok
2、创建共享内存 -> shmget
3、映射共享内存 -> shmat
4、共享内存读写
5、解除共享内存映射 -> shmdt
6、删除共享内存 -> shmctl

共享内存例子

Server.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>int main (void){key_t key;                  /*系统唯一性标识ipc*/int shmid;                  /*共享内存标识*/char  *shms;                /* 共享内存挂接后的地址, */   struct shmid_ds shmbuf;      pid_t p;                                        /*进程号*/key = ftok(".", 'a');                           /*生成系统唯一标识ipc*/if(key<0){perror("ftok failed");return 1;}shmid = shmget(key, 1024, IPC_CREAT|0600);      /*获得共享内存,大小为1024个字节*/if(shmid<0){perror("shmget failed");return 2;}shms = (char *)shmat(shmid, NULL, 0);           /*挂接共享内存*/printf("shmat success!\n");while(strlen(shms)==0){sleep(1);printf("%s\n",shms);}shmdt(shms);                                /*摘除共享内存*/printf("shmdt success!\n");shmctl(shmid,IPC_RMID,&shmbuf);             /*删除共享内存*/return 0;
}
Client.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>static char msg[]="你好,共享内存!\n";
int main (void){key_t key;                  /*系统唯一性标识ipc*/int shmid;                  /*共享内存标识*/char  *shmc;                /* 共享内存挂接后的地址, */   struct shmid_ds shmbuf;      pid_t p;                                        /*进程号*/key = ftok(".", 'a');                           /*生成系统唯一标识ipc*/if(key<0){perror("ftok failed");return 1;}shmid = shmget(key, 1024, IPC_CREAT|0600);      /*获得共享内存,大小为1024个字节*/if(shmid<0){perror("shmget failed\n");return 2;}shmc = (char *)shmat(shmid, NULL, 0);           /*挂接共享内存*/printf("shmat success!");memcpy(shmc, msg, strlen(msg) +1);          /*复制内容到共享内存*/shmdt(shmc);                                /*摘除共享内存*/printf("shmdt success!\n");shmctl(shmid,IPC_RMID,&shmbuf);             /*删除共享内存*/return 0;
}
Makefile
all:client server
client: client.o                                gcc -o client client.o
server: server.o                                gcc -o server server.o
clean:                                      rm -rf server client *.o
运行截图

先运行server

之后检查是否创建共享内存

运行client

检查共享内存是否被删除

传送门

进程间通信IPC-共享内存相关推荐

  1. [转]Linux 进程间通信:共享内存

    (上) 级别: 初级 郑彦兴 (mlinux@163.com), 国防科大攻读博士学位 2003 年 5 月 01 日 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B ...

  2. Linux进程间通信(四) - 共享内存

    共享内存的优势 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...

  3. 进程间通信(IPC)之内存映射mmap和共享内存shm

    一.共享内存shm 1 概念:多个进程的地址空间都映射到同一块物理内存,这样多个进程都能看到这块物理内存,实现进程间通信,而且不需要数据的拷贝,所以速度最快. 二.内存映射mmap 1 前言:先介绍一 ...

  4. 【Linux系统编程】进程间通信之共享内存

    00. 目录 文章目录 00. 目录 01. 共享内存概述 02. 共享内存函数 2.1 创建共享内存 2.2 共享内存映射 2.3 共享内存解除映射 2.4 共享内存操作函数 03. 案例实战 04 ...

  5. 进程间通信:共享内存概念及代码

    前言 接下讨论的IPC机制,它们最初由System V版本的Unix引入.由于这些机制都出现在同一个版本中并且有着相似的编程接口,所以它们被称为System V IPC机制.接下来的内容包括: 信号量 ...

  6. 进程间通信之-共享内存Shared Memory--linux内核剖析(十一)

    共享内存 共享内存是进程间通信中最简单的方式之中的一个. 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区. 共享内存同意两个或很多其他进程訪问同一块内存,就如同 malloc() 函数 ...

  7. 进程间通信之共享内存

    共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容. 共享内存实现分两个步骤: 1 ...

  8. Linux(信号,进程间通信)共享内存,信号量,消息队列

    信号(signal) 1.1 什么是信号? 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式 1.2 信号的来源 硬件 [1] 用户在终端按下某些键时,终端驱动程序会发送信号给前台进程 ct ...

  9. c语言编程基础之IPC共享内存

    共享内存(Shared Memory)是最简单的进程间通信方式,它允许多个进程访问相同的内存,一个进程改变其中的数据后,其他的进程都可以看到数据的变化. 共享内存是进程间最快速的通信方式: `进程共享 ...

  10. [IPC] 共享内存——分析和使用

    共享内存 共享内存简介 共享内存是所有进程间通信(IPC)手段中速度最快的,不同进程间使用事实上的同一内存区域,这样使得进程间使用信息时免去"复制"这一流程,减少开销. 以下面&q ...

最新文章

  1. Ubuntu里解压tar.xz格式
  2. JavaScript this指向相关内容
  3. 字典对中文字符串进行排序 python_Python基础入门:字符串和字典
  4. 怎么用python写数据库_如何使用python对数据库(mysql)进行操作
  5. canvas 元素绑定事件_绘制SVG内容到Canvas的HTML5应用
  6. 电子工程专业评副高总结_微电子科学与工程专业怎么样?
  7. 图像目标检测(Object Detection)原理与实现(一)
  8. nodejs实践录:基于koa的简单web服务器
  9. [转载] 使用Python在Pandas Dataframe中建立索引
  10. asp.net中控制反转的理解
  11. Centos 6.5安装python3.5.1
  12. 项目经理和产品经理的区别
  13. C#中的session用法
  14. 【Java编程】写一个将华氏温度转换成摄氏温度的程序,转换的公式是:°F = (9/5)*°C + 32 其中C表示摄氏温度,F表示华氏温度。
  15. 模拟人生4修改服务器,模拟人生4常用秘籍与修改技巧心得
  16. 系统弱口令检测与网络端口扫描
  17. thymeleaf中数字的日期格式以及货币格式
  18. UDS的19 04读取快照信息解析
  19. CONVERT转换函数
  20. 一款牛逼的Java工具类库,GitHub星标10.7k+,你敢用吗?

热门文章

  1. upfst是什么函数C语言,基于ST‑UPFNN算法的高含硫天然气净化工艺的动态演化建模方法与流程...
  2. python计算互信息_Maximal Information Coefficient (MIC)最大互信息系数详解与实现
  3. 普通高等学校高职高专教育指导性专业目录(试行)
  4. 高级转录组调控分析和R语言数据可视化第十四期 (线上线下开课)
  5. 多智能体强化学习(四)多智能体RL
  6. 抖音 -抖店开放平台 SDK 实现及项目工程
  7. 亚马逊云科技:一杯好牛奶背后的AI引擎
  8. html页面中常见的特殊符号,收集的web页面html中常用的特殊符号大全分享
  9. 随想录Day9--28. 实现 strStr() , 459.重复的子字符串
  10. Java多线程游戏仿真实例分享