共享内存的工作方式顾名思义,共享内存让一段内存可供多个进程访问。用特殊的系统调用(即对 UNIX 内核的请求)分配和释放内存并设置权限;通过一般的读写操作读写内存段中的数据。共享内存并不是从某一进程拥有的内存中划分出来的;进程的内存总是私有的。共享内存是从系统的空闲内存池中分配的,希望访问它的每个进程连接它。这个连接过程称为映射,它给共享内存段分配每个进程的地址空间中的本地地址。假设在同一系统上有两个进程 A 和 B 正在运行(见 图 1),它们可以通过共享内存进行协作和共享信息。在图中 A 和 B 采用不同大小的图形,以此强调应用程序不必相同。 图 1. 两个进程在同一个主机上运行,执行不同的代码 

在 图 2 中,进程 A 请求一个共享内存段。进程 A 对这个内存段进行初始化,让它准备好接受访问。这个过程还给内存段命名,让其他进程可以找到它。通常,内存段名称并不是动态分配的;而是众所周知的,比如使用头文件中的常量,其他代码可以方便地引用它。

图 2. 一个进程请求共享内存段

 

3。进程 A 把共享内存段连接(即映射)到自己的地址空间。进程 B 通过它的命名管道找到这个内存段,也把它映射到自己的地址空间,见 图 3。两个进程扩大了,表示包含共享内存段。

4.最后,在 图 4 中,进程 A 和 B 可以随意读写共享内存段。按照与本地进程内存相同的方式对待共享内存。read() 和 write() 的作用与一般情况下一样。

图 4. 两个或更多进程现在可以通过共同的内存共享数据

 

这些图中所示的许多工作可以通过 UNIX 共享内存 API 执行。实际上,有两套共享内存 API:POSIX API 和比较老(但是仍然有效)的 System V API。因为 POSIX 是 UNIX 和 Linux® 及其衍生系统上的公认标准,所以我们使用此版本。另外,POSIX API 使用简单的文件描述符执行读写,大家应该更熟悉。

POSIX 为创建、映射、同步和取消共享内存段提供五个入口点:

  • shm_open():创建共享内存段或连接到现有的已命名内存段。这个系统调用返回一个文件描述符。
  • shm_unlink():根据(shm_open() 返回的)文件描述符,删除共享内存段。实际上,这个内存段直到访问它的所有进程都退出时才会删除,这与在 UNIX 中删除文件很相似。但是,调用 shm_unlink() (通常由原来创建共享内存段的进程调用)之后,其他进程就无法访问这个内存段了。
  • mmap():把共享内存段映射到进程的内存。这个系统调用需要 shm_open() 返回的文件描述符,它返回指向内存的指针。(在某些情况下,还可以把一般文件或另一个设备的文件描述符映射到内存。对这些操作的讨论超出了本文的范围;具体方法请查阅操作系统的 mmap() 文档。)
  • munmap():作用与 mmap() 相反。
  • msync():用来让共享内存段与文件系统同步 — 当把文件映射到内存时,这种技术有用。

使用共享内存的过程是,用 shm_open() 创建内存段,用 write() 或 ftruncate() 设置它的大小,用 mmap() 把它映射到进程内存,执行其他参与者需要的操作。当使用完时,原来的进程调用 munmap() 和 shm_unlink(),然后退出。

示例应用程序

清单 1 给出一个简单的共享内存示例。(代码取自 John Fusco 撰写的 The Linux Programmer's Toolbox 一书 [由 Prentice Hall Professional 于 2007 年 3 月出版,ISBN 0132198576],已经得到出版商的使用授权。)代码实现通过共享内存段通信的父进程和子进程。

清单 1. 共享内存示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>void error_and_die(const char *msg) {perror(msg);exit(EXIT_FAILURE);
}int main(int argc, char *argv[]) {int r;const char *memname = "sample";const size_t region_size = sysconf(_SC_PAGE_SIZE);int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);if (fd == -1)error_and_die("shm_open");r = ftruncate(fd, region_size);if (r != 0)error_and_die("ftruncate");void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (ptr == MAP_FAILED)error_and_die("mmap");close(fd);pid_t pid = fork();if (pid == 0) {u_long *d = (u_long *) ptr;*d = 0xdbeebee;exit(0);}else {int status;waitpid(pid, &status, 0);printf("child wrote %#lx/n", *(u_long *) ptr);}r = munmap(ptr, region_size);if (r != 0)error_and_die("munmap");r = shm_unlink(memname);if (r != 0)error_and_die("shm_unlink");return 0;
}

下面是代码中的一些要点:

  • 对 shm_open() 的调用看起来应该很熟悉;它与 open() 函数很相似,包括初始化内存段和设置权限的方式。在这里,内存段是全局可读、全局可写的。如果调用成功,返回下一个未使用的文件描述符;否则,返回 -1 并相应地设置 errno
  • ftruncate() 把文件的大小设置为 region_size 字节,这以前设置为系统的标准页面大小。sysconf() 是 libc 的组成部分。(还可以使用 shell 工具 getconf 检查系统的配置设置。)
  • mmap() 连接共享内存段,返回用于对内存段直接读写字节的指针。PROT_READ 和 PROT_WRITE 分别表示可以读和写这个内存段中的页面。MAP_SHARED 表示对这个内存段的任何修改应该向所有参与共享的进程 “公开”,与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
  • 如果您使用过 fork(),那么应该熟悉代码的计算部分。执行 fork 之后,父进程和子进程获得打开的所有文件描述符和数据值的拷贝,所以指针对于它们都是有效的。但是,pid 不同。子进程获得 0,父进程获得子进程的进程 ID,这个变量的值决定执行哪个 if/then/else 分支。子进程向指针写一些字节,然后退出。父进程等待子进程退出,然后读取它写的数据。
  • 但是,在父进程退出之前,它必须释放共享内存。用 munmap() 和 shm_unlink() 完成这个步骤。

最后还有一点也是非常重要,在编译共享内存的程序时里面需要调用到shm_open,shm_unlink等函数,则需要在编译时加上-lrt

gcc -o test test.c
结果为:
  /tmp/ccaGhdRt.o(.text+0x23): In function `main':
  : undefined reference to `shm_open'
  /tmp/ccaGhdRt.o(.text+0x49): In function `main':
  : undefined reference to `shm_unlink'
  collect2: ld returned 1 exit status
  编译结果实际上是说,没include相应的头文件,或是头文件不存在(即系统不支持该库函数)
  但我man shm_open是可以找到帮助文件的(说明系统支持),原因何在???
  请注意一下man shm_open的帮助文件的最后几行:
  NOTES
   These functions are provided in glibc 2.2 and later. Programs using
   these functions must specify the -lrt flag to cc in order to link
   against the required ("realtime") library.
   POSIX leaves the behavior of the combination of O_RDONLY and O_TRUNC
   unspecified. On Linux, this will successfully truncate an existing
   shared memory object - this may not be so on other Unices.
   The POSIX shared memory object implementation on Linux 2.4 makes use of
  a dedicated file system, which is normally mounted under /dev/shm.
  如果你注意到的话,这样编译就能通过了:
  gcc -lrt -o test test.c
  其实就是要连接库的原因。

http://blog.csdn.net/liangkaiming/article/details/6240005

通过共享内存进行进程间通信相关推荐

  1. QT实现共享内存进行进程间通信

    QT实现共享内存进行进程间通信 项目简介 项目技术 项目展示 主要源码片段解析 获取完整项目源码传送门 项目简介 演示使用带有QSharedMemory类的共享内存进行进程间通信. 共享内存示例显示了 ...

  2. java 共享内存ipc_进程间通信——IPC之共享内存

    共享内存是三个IPC机制中的一个.它允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式. 大多数的共享内存的实现,都把由不同进程之间共享的内存安排为 ...

  3. python进程共享内存_Python进程间通信之共享内存

    前一篇博客说了怎样通过命名管道实现进程间通信,但是要在windows是使用命名管道,需要使用python调研windows api,太麻烦,于是想到是不是可以通过共享内存的方式来实现.查了一下,Pyt ...

  4. linux 共享内存_linux进程间通信----IPC篇(一)----共享内存初识篇

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 what 所 ...

  5. C语言 共享内存实现进程间通信

    1.c // ..使用内存映射可以拷贝文件 /* 对原始文件进行内存映射 创建一个新文件 把新文件的数据拷贝映射到内存中 通过内存拷贝将第一个文件的内存映射区拷贝到第二个文件的内存映射区 释放资源 * ...

  6. python多进程共享内存_python 进程间通信 共享内存

    python多进程通信实例分析 python多进程通信实例分析操作系统会为每一个创建的进程分配一个独立的地址空间,不同进程的地址空间是完全隔离的,因此如果不加其他的措施,他们完全感觉不到彼此的存在.那 ...

  7. java 内存映射文件进程间通讯_[转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile...

    进程间的通信方式有很多种, 上次我们说了最傻瓜的"共享外存/文件"的方法. 那么, 在本文中, 我们即将学习"共享内存"的方式实现进程间的通信, 这是IPC最快 ...

  8. linux c之使用共享内存实现进程间通信

    这篇博客有别人的也有自己改的,作为读书笔记,勿喷. 1.共享内存的介绍 共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进 ...

  9. linux java 共享内存_Linux进程间通信之共享内存

    一,共享内存 内核管理一片物理内存,允许不同的进程同时映射,多个进程可以映射同一块内存,被多个进程同时映射的物理内存,即共享内存. 映射物理内存叫挂接,用完以后解除映射叫脱接. 1,共享内存的特点: ...

最新文章

  1. 内存管理-定时器循环、内存布局、tagged pointer、weak指针、copy、自动释放池
  2. 无线传输层安全协议WTLS安全机制详解
  3. 【数据挖掘】数据挖掘建模 ( 预测建模 | 描述建模 | 预测模型 | 描述模型 | 判别模型 | 概率模型 | 基于回归的预测模型 )
  4. CodeForce 534C Polycarpus' Dice (数学推理)
  5. 浅谈数据分析中的“暗物质”
  6. .Net Micro Framework SDK 2.5 发布
  7. 21 PP配置-生产计划-定义计划订单编号范围
  8. day21 java的数字类
  9. 世达工具编号查询_世达工具型号-名称对照表
  10. photoshop改变图片大小,不改变像素
  11. T-SQL笔记8:索引
  12. python监控钉钉群消息_使用python对mysql主从进行监控,并调用钉钉发送报警信息...
  13. Oracle账户被锁定后如何解锁
  14. 我为什么鼓励工程师写博客
  15. 阿里云大数据+AI技术沙龙上海站回顾 | ​揭秘TPC-DS 榜单第一名背后的强大引擎...
  16. 敏捷物联——引领生产和服务创新
  17. 多测师肖sir_高级金牌讲师_项目数据
  18. labview虚拟心电监测系统_基于LabVIEW实现的心电监护系统
  19. 一亿个对象过滤,要求内存占用小于1G
  20. jupyter的安装步骤

热门文章

  1. python打包成exe闪退_脚本程序打包后,黑框一闪而过,程序不能运行
  2. 2016江苏计算机二级考试时间,2016年江苏计算机二级考试报名时间_无忧考网.pdf...
  3. 测试录制的电话拨码声音信号在发送过程中的问题
  4. Python - 移除List中重复项的五种常用方法
  5. 2021年春季学期-信号与系统-第十二次作业参考答案-第二小题
  6. php参数一个字符串数组,PHP字符串控制台参数到数组
  7. ios 裁剪圆形头像_iOS开发笔记:实现圆形头像
  8. python重复执行_python flask schedule重复运行 任务被重复执行问题 解决方案
  9. 网络编程大小端的注意事项
  10. affectnet数据集_处理表情识别中的坏数据:一篇CVPR 2020及两篇TIP的解读