Linux学习笔记(14)-进程通信|共享内存
在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)-进程通信|共享内存的更多相关文章
- Linux学习笔记(六) 进程管理
1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...
- linux io 学习笔记(03)---共享内存,信号灯,消息队列
system V IPC 1)消息队列 2)共享内存 3)信号灯(信号量集) 1.消息队列. ipcs -q 查看系统中使用消息队列的情况 ipcrm -q +msqid 删除消息队列 消息队列工作原 ...
- Linux学习笔记14——使用fcntl实现文件锁定
期末考试快要来了,Linux学习进度一下拉下来许多.今天学习的是文件锁定,在Linux中,实现文件锁定的方法很多,例如fcntl和lockf.下面主要是fcntl的调用. fcntl函数的原型是:in ...
- Windows进程通信 -- 共享内存(1)
共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 W ...
- Windows进程通信 -- 共享内存
享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 Wi ...
- Windows进程通信-共享内存空间
三个模块 1,game.exe,三个方法,控制台输入指令('A','B','R')分别控制三个方法的调用: 2,WGDll.dll,要注入到game进程中的dll文件: 3,myconsole.exe ...
- linux学习笔记之进程
一.基础知识 1:进程. 1,进程ID: 非负整数,具有唯一性. 1)ID=0的进程:调度进程/交换进程.内核的一部分.不执行任何磁盘上的程序. 2)ID=1的进程:init进程. 1-自举结束时,由 ...
- Linux学习笔记24——进程管道
一 管道的作用 通常把一个进程的输出通过管道连接到另一个进程的输入. 二 popen和pclose函数 #include <stdio.h> FILE *popen(const char ...
- linux学习笔记-13.进程控制
1.查看用户最近登录情况 lastlastlog 2.查看硬盘使用情况 df 3.查看文件大小 du 4.查看内存使用情况 free 5.查看文件系统 /proc 6.查看日志 ls /var/log ...
随机推荐
- 第一届山东省ACM——Phone Number(java)
Description We know that if a phone number A is another phone number B’s prefix, B is not able to be ...
- [原创]Matlab2016b打包为C++的lib文件
这几天在研究如何将Matlab的程序导入到C++进行调用. 由于需要使用到不少Matlab函数,所以之前就有些担心这些函数在导出后是否能够继续使用.不过之后觉得既然已经导出成了一个单独文件,相关运算应 ...
- 关于firefox对font awesome本地环境无法加载问题
问题描述 昨天尝试使用font awesome加载字体图标,直接在本地引入相关文件,测试发现图标在chrome和IE环境支持,但是在firefox上怎么都显示不出来. 解决方法 通过测试发现通过htt ...
- JavaScript对象详解
JavaScript中的数据类型作为javascript的核心,我们经常要用到,也是最基础的. javascript中有非常复杂的数据类型:包括对象(Object)数据类型,还有五个基本数据类型(N ...
- MiniProfiler
1.安装MiniProfiler包 PM> Install-Package MiniProfiler 2.在Views下的web.config中引入命名空间: <pages pageBas ...
- PHP 正则表达式 修饰符
下面列出了当前可用的 PCRE 修饰符.括号中提到的名字是 PCRE 内部这些修饰符的名称. 模式修饰符中的空格,换行符会被忽略,其他字符会导致错误. i (PCRE_CASELESS) 如果设置了这 ...
- web 安全杂谈
以前写过一篇关于session.cookie的博文,都是简单的介绍.不过session和cookie和网络安全可有着密切的关系. 今天主要从这几个方面总结下最近学到的东西: 1. session 两种 ...
- N皇后问题—初级回溯
N皇后问题,最基础的回溯问题之一,题意简单N*N的正方形格子上放置N个皇后,任意两个皇后不能出现在同一条直线或者斜线上,求不同N对应的解. 提要:N>13时,数量庞大,初级回溯只能保证在N< ...
- 耿丹CS16-2班第二次作业汇总
-- Deadline: 2016-09-28 12:00 -- 作业内容:http://www.cnblogs.com/huangjunlian/p/5891726.html -- 第二次作业总结: ...
- powershell使用
主要语法点: -match -notmatch -replace -join -split -and -or -xor -not ! +.-.*./.% =.+=.-=.*=./=.%= -eq.-n ...