进程间通信(四)—共享内存
2016-07-08 00:48
267 查看
我会用几篇博客总结一下在Linux中进程之间通信的几种方法,我会把这个开头的摘要部分在这个系列的每篇博客中都打出来
进程之间通信的方式
管道
消息队列
信号
信号量
共享存储区
套接字(socket)
进程间通信(五)—信号传送门:/article/11898702.html
进程间通信(三)—信号量传送门:/article/11898704.html
进程间通信(二)—消息队列传送门:/article/11898705.html
进程间通信(一)—管道传送门:/article/11898706.html
这篇主要记录的是共享存储区的相关操作,说是共享存储区,其实就是共享内存,进程拥有的能互相通信存储区也就有内存了吧
为什么用共享存储区进行通信?因为快!管道是文件,操作慢,消息队列创建操作都有消耗所以慢,共享内存是要创建好两个进程都可以直接对这块内存进行操作,互相都是可见的。
为什么用共享存储区编写程序?因为接口简单!操作绝对比消息队列简单好多。
[b]创建共享存储区[/b]
虽然感觉很简单的事情,但是还是要创建开辟一下,不然每个进程都用自己的地址空间映射到不同的物理地址,哪怕虚拟地址是一样的,也是各自独立的,互相不可见,声明了这个共享存储区之后,才可以往这个公共的区域映射(这样才有用不是么)。
函数原型:int shmget(key_t key, size_t size, int shmflg);
头文件:#include <sys/ipc.h> #include <sys/shm.h>
参数解析
key参数通过ftok函数的返回值取得,或者传入IPC_PRIVATE由操作系统自动分配
size表示你要开辟多大的共享存储空间,PS:分配空间最终会变成分配物理空间,是通过分配整页的方式实现的,Linux系统下一页大小是4KB=4096B,小于4096B则分配一页,size传入4097则分配两页
shmflg有IPC_CREAT 和 IPC_EXCL
调用这个函数就可以开辟一个共享存储区了,可以通过ipcs -m查看当前共享存储区状态
第一个键值就是传入的key,shmid标识唯一共享内存段,拥有者权限字节就不多说了额,这个nattch是指当前有多少个进程连接到该共享存储区
nattch:只创建共享存储区是不够的,你需要把它和进程链接,才能让进程的地址空间中的一段地址映射到共享内存段上。
[b]共享存储区的连接[/b]
这就讲一下用什么函数链接共享存储区,需要注意的是,两个进程都需要链接才可以,创建共享存储区的进程不会自动连接,也需要调用链接函数
函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
头文件:#include <sys/types.h> #include <sys.shm.h>
参数解析
shmid表示共享存储区的标识
第二个参数表示共享存储区的开始地址,如果不是对内存十分了解建议交给操作系统去做,设置为0
shmflg可以设置当前进程的读写权限,SEM_RDONLY之类的,默认0为读写均可,测试程序我给了0
每有一个进程调用这个函数,就会使nattch增加1,返回值因为是个空类型的指针常常需要强制转换
[b]共享存储区的链接的断开[/b]
链接使用完之后就断开是个好习惯,而且对销毁共享存储空间也好
函数原型:int shmdt(const void *shmaddr);
头文件:#include <sys/types.h> #include <sys.shm.h>
参数解析删除共享存储区
就是要删除的共享存储区的起始地址,因为是空类型的指针,没必要转换,直接给来都能删除
[b]删除共享存储区[/b]
最后还是要用到shmctl函数来删除共享存储区
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
头文件:#include <sys/ipc.h> #include <sys/shm.h>
参数解析
shmid表示共享存储区的标识
cmd给出IPC_RMID表示删除
因为第二个参数设置为IPC_RMID表示删除,第三个参数没用了,第三个参数直接给NULL(0)
事已至此,基本操作就说完了,废话少说,show me the code
我的程序分为comm.h(公共头文件) comm.c(封装基本函数) server.c(简易服务器端) 一共3个文件
功能主要实现了简单的字符串共享?父进程写入,子进程打印,就这么简单
结果图并看不出什么鬼
comm.h
comm.c
server.c
进程之间通信的方式
管道
消息队列
信号
信号量
共享存储区
套接字(socket)
进程间通信(五)—信号传送门:/article/11898702.html
进程间通信(三)—信号量传送门:/article/11898704.html
进程间通信(二)—消息队列传送门:/article/11898705.html
进程间通信(一)—管道传送门:/article/11898706.html
这篇主要记录的是共享存储区的相关操作,说是共享存储区,其实就是共享内存,进程拥有的能互相通信存储区也就有内存了吧
为什么用共享存储区进行通信?因为快!管道是文件,操作慢,消息队列创建操作都有消耗所以慢,共享内存是要创建好两个进程都可以直接对这块内存进行操作,互相都是可见的。
为什么用共享存储区编写程序?因为接口简单!操作绝对比消息队列简单好多。
[b]创建共享存储区[/b]
虽然感觉很简单的事情,但是还是要创建开辟一下,不然每个进程都用自己的地址空间映射到不同的物理地址,哪怕虚拟地址是一样的,也是各自独立的,互相不可见,声明了这个共享存储区之后,才可以往这个公共的区域映射(这样才有用不是么)。
函数原型:int shmget(key_t key, size_t size, int shmflg);
头文件:#include <sys/ipc.h> #include <sys/shm.h>
参数解析
key参数通过ftok函数的返回值取得,或者传入IPC_PRIVATE由操作系统自动分配
size表示你要开辟多大的共享存储空间,PS:分配空间最终会变成分配物理空间,是通过分配整页的方式实现的,Linux系统下一页大小是4KB=4096B,小于4096B则分配一页,size传入4097则分配两页
shmflg有IPC_CREAT 和 IPC_EXCL
调用这个函数就可以开辟一个共享存储区了,可以通过ipcs -m查看当前共享存储区状态
第一个键值就是传入的key,shmid标识唯一共享内存段,拥有者权限字节就不多说了额,这个nattch是指当前有多少个进程连接到该共享存储区
nattch:只创建共享存储区是不够的,你需要把它和进程链接,才能让进程的地址空间中的一段地址映射到共享内存段上。
[b]共享存储区的连接[/b]
这就讲一下用什么函数链接共享存储区,需要注意的是,两个进程都需要链接才可以,创建共享存储区的进程不会自动连接,也需要调用链接函数
函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
头文件:#include <sys/types.h> #include <sys.shm.h>
参数解析
shmid表示共享存储区的标识
第二个参数表示共享存储区的开始地址,如果不是对内存十分了解建议交给操作系统去做,设置为0
shmflg可以设置当前进程的读写权限,SEM_RDONLY之类的,默认0为读写均可,测试程序我给了0
每有一个进程调用这个函数,就会使nattch增加1,返回值因为是个空类型的指针常常需要强制转换
[b]共享存储区的链接的断开[/b]
链接使用完之后就断开是个好习惯,而且对销毁共享存储空间也好
函数原型:int shmdt(const void *shmaddr);
头文件:#include <sys/types.h> #include <sys.shm.h>
参数解析删除共享存储区
就是要删除的共享存储区的起始地址,因为是空类型的指针,没必要转换,直接给来都能删除
[b]删除共享存储区[/b]
最后还是要用到shmctl函数来删除共享存储区
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
头文件:#include <sys/ipc.h> #include <sys/shm.h>
参数解析
shmid表示共享存储区的标识
cmd给出IPC_RMID表示删除
因为第二个参数设置为IPC_RMID表示删除,第三个参数没用了,第三个参数直接给NULL(0)
事已至此,基本操作就说完了,废话少说,show me the code
我的程序分为comm.h(公共头文件) comm.c(封装基本函数) server.c(简易服务器端) 一共3个文件
功能主要实现了简单的字符串共享?父进程写入,子进程打印,就这么简单
结果图并看不出什么鬼
comm.h
#include <stdio.h> #include <sys/types.h> #include <string.h> #include <sys/ipc.h> #include <unistd.h> #include <sys/shm.h> #include <errno.h> #include <stdlib.h> #define _PATH_NAME_ "/tmp" #define _PROJ_ID_ 0x6666 static int comm_create_ssm(int flags,size_t size); int create_shm(size_t size); int get_shm(); char *shm_at(int shm_id); void destory_shm(int shm_id); int shm_dt(char *addr);
comm.c
#include "comm.h" static int comm_create_shm(int flags,size_t size) { key_t _key=ftok(_PATH_NAME_,_PROJ_ID_); if(_key<0) { printf("%d:%s",errno,strerror(errno)); } int shm_id; if((shm_id=shmget(_key,size,flags))<0) { printf("shmget error,%d:%s",errno,strerror(errno)); } return shm_id; } int create_shm(size_t size) { int flags=IPC_CREAT |IPC_EXCL; return comm_create_shm(flags,size); } int get_shm() { int flags=IPC_CREAT; return comm_create_shm(flags,0); } char *shm_at(int shm_id) { return (char *)shmat(shm_id,NULL,0); } int shm_dt(char *addr) { return shmdt(addr); } void destory_shm(int shm_id) { shmctl(shm_id,IPC_RMID,0); }
server.c
#include "comm.h" int main() { int pid=fork(); if(pid>0) { //father int shm_id=create_shm(4096); char *buf=shm_at(shm_id); int i=0; while(i<4096) { sleep(1); buf[i]='A'; i++; buf[i]='\0'; } } else { //child int shm_id=get_shm(); char *buf=shm_at(shm_id); while(1) { sleep(1); printf("%s\n",buf); } } return 0; }
相关文章推荐
- 关于css的布局
- Java容器的特点与接口中的方法
- 看板与组织重组 1
- 学IT看教程的学习网站
- iOS 开发的大纲
- Android RecyclerView 实现快速滑动
- Orleans之Hello World
- ThinkPHP之疑难杂症(六)——Mac终端设置定时任务
- The java.util.concurrent Synchronizer Framework
- HDU 1865 1sting
- Gradle version 2.20 is required. Current version is 2.10 解决方法
- 星空战神游戏策划案
- java五子棋判断输赢算法
- VS2010 Win7 64位 C++ MFC DataGrid绑定实例
- SPSS——均 值 检 验 (Compare Means)——均值过程
- bresenham 算法介绍
- java五子棋初实现
- 分布式服务框架 Zookeeper -- 管理分布式环境中的数据
- 自己的一些车机app 界面
- 有return的情况下try catch finally的执行顺序(最有说服力的总结)