在Linux中,共享内存是允许两个不相关的进程访问同一个逻辑内存的进程间通信方法,是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。

  不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址。

  就好像它们是由用C语言malloc()分配的内存一样。

  建立一个共享内存大概有五个步骤:

  1.调用shm_open()函数,在指定一个内存的名字,用来创建或者打开一个共享内存

  2.调用mmap()函数,把共享内存映射在进程的空间里

  3.调用fturncate()函数来分配共享内存的大小

  在使用完共享内存之后,还得经过下面两个步骤,将内存关闭并释放

  4.调用munmap()函数,取消共享内存的映射

  5.调用shm_unlink()函数来删除共享内存

  函数介绍

  shm_open()

  这个函数关联的头文件是sys/mman.h,sys/stat.h,fcntl.h

  函数原形如下:fd shm_open(const char *name,int oflag, mode_t mode)

  参数name很好理解,就是指定一个名字,用来标识共享内存

  参数oflag的作用在于指定属性,比如新建,打开,只读,只写等等

  参数mode的作用那就很明显了,是用来指定新建内存的权限,这个参数只有在新建共享内存时才有用

————————————————————————————————————————————————

  新创建或者打开的共享内存的大小是0.必须在指定大小之后才能正常的使用,这里用来指定内存大小的函数是:

  ftruncate()

  这个函数关联的头文件有unistd.h,sys/types.h

  函数原形如下:ftruncate(int fd,off_t length)

  参数fd自然就是内存文件的句柄(Linux中,一切都被当做文件来使用,内存当然也不例外)

  length参数便是用来指定内存的大小了,单位是字节

————————————————————————————————————————————————

  在设置完内存的大小后,依然还是不能直接使用,还需要一个步骤,那就是设置内存映射。

  mmap()

  这个函数关联的头文件有sys/mman.h

  函数原形如下:void * mmap(void *addr, size_t length, int port, int flags, int fd, off_t offset)

  参数addr 设置共享内存的起点,如果将其设置为NULL的话,那就意味是由系统自动分配

  参数length就很好理解了,就是共享内存的大小

  参数port是用来设置共享内存的权限,设置属性和open差不多,但不能超过shm_open所设置的权限

  flag是设置一些特殊的要求,比如MAP_FIXED,要求返回值必须等于addr。MAP_SHARED多个进程对同一文件的映射是共享的,

  其中一个进程对映射做了修改,那么别的进程也能看到(这段话暂时还不理解)。

  参数fd,不多解释,就是内存文件的句柄

  参数offset,要映射字节在文件中的偏移

————————————————————————————————————————————————

  在有了以上三个函数之后,基本上就能在进程之间建立一个共享内存了。至于取消内存和删除内存的函数,那就更加简单,这里不在多说。

  程序实例

  现在实现一个功能,在两个完全不相干的进程中建立一个共享内存,其中一个进程在向一段内存中写入一个数字,另个一进程读取这个数字。

  

#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<unistd.h> #define SHM_SIZE 10
#define SHM_NAME "shmname" int main(void)
{
int fd;
char * prt; fd = shm_open(SHM_NAME,O_RDWR|O_CREAT,);
if (fd < )
{
printf("创建共享内存失败!\n");
exit(-);
} fturncate(fd,SHM_SIZE);//设置共享内存的大小为10
prt = mmap(NULL, SHM_SIZE, 0x777, MAP_SHARED, fd,);
if (prt == MAP_FAILED)
{
printf("创建共享内存映射失败!\n");
exit(-);
} *prt = ;
munmap(prt,SHM_SIZE);
shm_unlink(SHM_NAME); return ;

  以上便是代码,现在写完了Makefile之后进行编译,但是在编译中出现了很奇怪的问题。

  

  难道是我把这三个函数的名字打错了吗?

  仔细检查之下,还真有打错的!!!(ftruncate函数打成了fturncate,真是粗心啊!!!)

  把这个函数修改之后,依然不通过,这是什么原因?

  经过我的分析,从编译结果上来看,应该不在是语法上出的问题了……

  开始调查……

  在一个大神的资料中看见这么一句话,我仿佛是看见了救星:

  

好吧,原来是这个问题!那么开始修正Makefile。

  

  编译还是没有通过,这是怎么回事?

  继续调查……

  半小时后,终于发现了愿意,原来Linux在编译中,首先是从最后面开始进行连接,所以把-lrt放在编译指令的中间是不可以的,一定要放在最后面。

  (不要问我为什么,我也不知道)

  等我把它放在最后,就能编译通过了!

  

  现在写数据的进程已经写完了,开始写读数据的进程。

  

#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h> #define SHM_SIZE 10
#define SHM_NAME "shmname" int main(void)
{
int fd;
char * prt; fd = shm_open(SHM_NAME, O_CREAT|O_TRUNC|O_RDWR, );
if (fd < )
{
printf("进程2创建共享内存失败!%d\n",errno);
exit(-);
} ftruncate(fd,SHM_SIZE);//设置共享内存的大小为10
prt = mmap(NULL, SHM_SIZE, 0x777, MAP_SHARED, fd,);
if (prt == MAP_FAILED)
{
printf("创建共享内存映射失败!\n");
exit(-);
}
while(*prt != )
{
sleep();
}
printf("读出数据prt为=%d.\n",*prt);
munmap(prt,SHM_SIZE); return ; }

  两个代码都做完了,现在开始编译……完美!

  开始运……啊!!!

  这又怎么啦?

  

  怎么会创建内存失败呢?

  创建共享内存,为什么回返回errno 13呢?

  找了半天,终于找到了问题的原因,原来是因为我在之前代码还不完善的时候,创建了一个名为shmname的内存,

  

  然后又没能把他删掉,而且它的权限还高的吓人,导致它一直存在于/dev/shm路径下,所以等代码完善之后,在运行程序就会发现因为没有权限而运行失败了。

  手动把那个名为shmname的东西删掉后,再次运行程序……OK!!

  

  ————————————————————————————————————————————————————

  本节重点:

  1.在编译共享内存的代码时,要在编译命令的最后面加上-lrt,用来连接库

  2.如果在运行创建共享内存程序时发生errno = 13的错误,可能就是我刚才遇见的错误,在/dev/shm路径下已经有一段同名的共享内存了,

    需要手动删除,或者换一个名字。

  

  

    

Linux学习笔记(14)-进程通信|共享内存的更多相关文章

  1. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  2. linux io 学习笔记(03)---共享内存,信号灯,消息队列

    system V IPC 1)消息队列 2)共享内存 3)信号灯(信号量集) 1.消息队列. ipcs -q 查看系统中使用消息队列的情况 ipcrm -q +msqid 删除消息队列 消息队列工作原 ...

  3. Linux学习笔记14——使用fcntl实现文件锁定

    期末考试快要来了,Linux学习进度一下拉下来许多.今天学习的是文件锁定,在Linux中,实现文件锁定的方法很多,例如fcntl和lockf.下面主要是fcntl的调用. fcntl函数的原型是:in ...

  4. Windows进程通信 -- 共享内存(1)

    共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 W ...

  5. Windows进程通信 -- 共享内存

    享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 Wi ...

  6. Windows进程通信-共享内存空间

    三个模块 1,game.exe,三个方法,控制台输入指令('A','B','R')分别控制三个方法的调用: 2,WGDll.dll,要注入到game进程中的dll文件: 3,myconsole.exe ...

  7. linux学习笔记之进程

    一.基础知识 1:进程. 1,进程ID: 非负整数,具有唯一性. 1)ID=0的进程:调度进程/交换进程.内核的一部分.不执行任何磁盘上的程序. 2)ID=1的进程:init进程. 1-自举结束时,由 ...

  8. Linux学习笔记24——进程管道

    一 管道的作用 通常把一个进程的输出通过管道连接到另一个进程的输入. 二 popen和pclose函数 #include <stdio.h> FILE *popen(const char ...

  9. linux学习笔记-13.进程控制

    1.查看用户最近登录情况 lastlastlog 2.查看硬盘使用情况 df 3.查看文件大小 du 4.查看内存使用情况 free 5.查看文件系统 /proc 6.查看日志 ls /var/log ...

随机推荐

  1. jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)

    今天学习jQuery,看到nth-child(even)用法,特意找了下这个选择器的用法,在CSS3标准中,用法很强大. 对此,我把CSS3标准中nth-child()用法大致介绍下: CSS3伪类选 ...

  2. 【Unity3d】3d网页游戏场景打包与加载

    http://www.cnblogs.com/dosomething/archive/2012/04/07/2436353.html 3d游戏中  一个场景往往比较大  如果游戏的进行需要下载一个10 ...

  3. CSS & JS 制作滚动幻灯片

    ==================纯CSS方式==================== <!DOCTYPE html> <html> <head> <met ...

  4. Activity系列讲解---数据传递

    在Android中,不同的Activity实例可能运行在一个进程中,也可能运行在不同的进程中.因此需要一种特别的机制帮助我们在Activity之间传递消息.Android中通过Intent对象来表示一 ...

  5. 各种Android手机Root方法

    Root的介绍  谷歌的android系统管理员用户就叫做root,该帐户拥有整个系统至高无上的权利,它可以访问和修改你手机几乎所有的文件,只有root才具备最高级别的管理权限.我们root手机的过程 ...

  6. Unity NGUI添加UIRoot

    导入NGUI包后,菜单多出一个选项 "NGUI",选择其子选项 "options" -- "Reset Prefab ToolBar" ,在 ...

  7. ACM/ICPC 之 三维计算几何+暴力枚举+判重(HDU5839)

    CCPC网赛第八题,求立体几何数量,题解见注释 //立体几何-求满足要求的四面体个数 //要求1:至少4条边相等 //要求2:四条边相等时,另两条边一定不相邻(即对边) //题解:以当前边为不相邻的其 ...

  8. js_面向对象

    面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装.继承.多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标准定义J ...

  9. UIButton无法响应点击事件

    一.问题描述 因为项目需要,需要UITableView上添加固定的筛选表头,一直固定,不能随UITableView滚动.所以直接将表头与UITableView分离,将它添加到控制器的UIView上,即 ...

  10. LINUX下YUM源配置

    转自:http://www.cnblogs.com/phoebus0501/archive/2010/12/14/1906144.html 1.确保RHEL5中已经安装了yum [root@lvs-m ...