进程间通信---共享内存
来源:互联网 发布:音乐变调器软件 编辑:程序博客网 时间:2024/05/18 20:12
一、IPC(Inter-Process Communication,进程间通信)对象的介绍
System V 的IPC对象有共享内存、消息队列、信号灯。
二、共享内存的介绍
注意:在IPC的通信模式下,不管是使用消息队列还是共享内存,甚至是信号灯,每个IPC的对象都有唯一的名字,称为"键"(key)。通过"键",进程能够识别所用的对象。"键"与IPC对象的关系就如同文件名称于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够公用一个文件。而在 IPC的通讯模式下,通过"键"的使用也使得一个IPC对象能为多个进程所共用。
<1>共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。
<2>为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。进程就可以直接读写这一块内存而不需要进行数据的拷贝,从而大大提高效率。
<3>由于多个进程共享一段内存,因此也需要依靠某种同步机制。
三、共享内存的特点
四、共享内存的操作流程
<1>创建/打开共享内存
<2>映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
<3>撤销共享内存映射
<4>删除共享内存对象
五、相关API
A.获取一块共享内存
功能:分配一块共享内存
返回值:
调用成功返回一个shmid(类似打开一个或创建一个文件获得的文件描述符一样);
调用失败返回-1。
参数说明:
<1>key标识共享内存的键值(就像文件的标识是文件名):0 / IPC_PRIVATE。
当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;
如果key的取值为0,而参数shmflg中设置了IPC_CREATE这个标志,则同样创建一块新的共享内存。
通过这种方式分配的共享内存,一般用来亲缘关系的进程间通信。
注意:我们一般是通过ftok这个函数获取键值
功能 : 获取一个IPC对象的键值
参数说明:
pthname就是你指定文件名的路径(该文件必须是存在而且可以访问的),一般情况我们都写一个目录
proj_id : 和pthname一起完成创建键值的参数,虽然为int,但是只有8个比特被使用。一般我们写一个字符代替。
例如:
案例:
运行的结果:
运行的结果:
<2>size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一个进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE = 4096字节)。
<3>shmflg有效的标志包括IPC_CREAT 和IPC_EXCL,他们的功能与open()的O_CREAT和O_EXCL相当。
IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则直接打开已存在的
IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误
例子一:假设键值为key,创建一个共享内存大小为4k,访问权限为066,如果已经存在则返回其标识号
int shmid;
if( (shmid = shmget(key,4 * 1024,0666 | IPC_CREAT)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE)
}
例子二、假设键值为key,创建一个共享内存大小为1k,访问权限为0666,如果已经存在则报错
int shmid;
if((shmid = shmget(key,1024,0666 | IPC_CREAT | IPC_EXCL)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE);
}
B.共享内存的映射
函数shmat将标识号为shmid共享内存映射到调用进程的地址空间中。
参数说明:
shmid : 要映射的共享内存区标识符
shmaddr : 将共享内存映射到指定地址(若为NULL,则表示由系统自动完成映射)
shmflg : SHM_RDONLY 共享内存只读
默认0:共享内存可读写。
返回值 :调用成功放回映射后的地址 ,出错放回(void *)-1;
C.取消共享内存与用户进程之间的映射
参数shmaddr是shmat映射成功放回的地址。
注意:当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的shm_nattch域的值减1,当这个值为0时,内核才从物理上删除这个共享段。
D.控制共享内存
参数说明:
shmid 共享内存标识ID
cmd IPC_STAT得到共享内存的状态
IPC_SET改变共享内存的状态
IPC_RMID删除共享内存
buf 是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定;
注意:
1.IPC_RMID命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生最后一个进程离开这个共享段时。
2.当cmd为IPC_RMID时,第三个参数应为NULL。呵呵,大部分我们都是这样做,用这个函数删除共享内存。
案例探究:
运行结果:
点击(此处)折叠或打开
- #include <sys/shm.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <semaphore.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #define BUFF_SIZE 1024
- int father_do_work(int shmid)
- {
- char *buf;
- void *shmaddr;
- sem_t *prsem;
- sem_t *pwsem;
- //有名信号量
- if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
-
- //有名信号量
- if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- //映射共享内存
- if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
- {
- perror("Fail to shmat");
- exit(EXIT_FAILURE);
- }
- buf = (char *)shmaddr;
- while(1)
- {
- if(sem_wait(pwsem) < 0)
- {
- perror("Fail to sem wait");
- break;
- }
- printf(">");
- fgets(buf,BUFF_SIZE,stdin);
- buf[strlen(buf) - 1] = '\0';
-
- if(sem_post(prsem) < 0)
- {
- perror("Fail to sem post");
- break;
- }
-
- if(strncmp(buf,"quit",4) == 0)
- {
- if(shmdt(shmaddr) < 0)
- {
- perror("Fail to shmaddr");
- exit(EXIT_FAILURE);
- }
- break;
- }
-
- usleep(500);
- }
-
- return 0;
- }
- int child_do_work(int shmid)
- {
- char *buf;
- void *shmaddr;
- sem_t *prsem;
- sem_t *pwsem;
- //
- if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
- {
- perror("Fail to sem open");
- return -1;
- }
- //映射共享内存
- if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
- {
- perror("Fail to shmat");
- exit(EXIT_FAILURE);
- }
- buf = (char *)shmaddr;
- while(1)
- {
- if(sem_wait(prsem) < 0)
- {
- perror("Fail to prsem");
- break;
- }
- printf("read buf : %s.\n",buf);
- if(sem_post(pwsem) < 0)
- {
- perror("Fail to pwsem");
- break;
- }
- if(strncmp(buf,"quit",4) == 0)
- {
- if(shmdt(shmaddr) < 0)
- {
- perror("Fail to shmaddr");
- exit(EXIT_FAILURE);
- }
- break;
- }
- }
-
- return 0;
- }
- int main()
- {
- int shmid;
- int pid;
- void *shmaddr;
-
- //创建共享内存
- if((shmid = shmget(IPC_PRIVATE,BUFF_SIZE,0666 | IPC_CREAT)) < 0)
- {
- perror("Fail to shmget");
- exit(EXIT_FAILURE);
- }
- if((pid = fork()) < 0)
- {
- perror("Fail to fork");
- exit(EXIT_FAILURE);
-
- }else if(pid == 0){
-
- child_do_work(shmid);
-
- }else{
-
- father_do_work(shmid);
- wait(NULL);
- if(shmctl(shmid,IPC_RMID,NULL) < 0)
- {
- perror("Fail to shmctl");
- exit(EXIT_FAILURE);
- }
- }
- exit(EXIT_SUCCESS);
- }
运行结果:
0
上一篇:Linux网络编程:原始套接字的魔力【上】
下一篇:进程间通信--信号(进程间通信唯一的异步方式)
相关热门文章
- softRoCE/RDMA 安装与测试...
- 利用进程信息追查内存泄漏...
- 追踪源码揪出mysql崩溃的真凶...
- kjournald进程占用了大量CPU...
- MySQL新特性之mysql_config_ed...
- linux 常见服务端口
- xmanager 2.0 for linux配置
- 【ROOTFS搭建】busybox的httpd...
- openwrt中luci学习笔记
- 什么是shell
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 进程间通信-共享内存
- 进程间通信---共享内存
- 进程间通信--共享内存
- 进程间通信--共享内存
- 进程间通信-共享内存
- 进程间通信共享内存
- 进程间通信-共享内存
- 进程间通信---共享内存
- 进程间通信----共享内存
- 【进程间通信】共享内存
- 进程间通信共享内存
- 进程间通信----共享内存
- 进程间通信---共享内存
- 进程间通信--------共享内存
- 进程间通信---共享内存
- 进程间通信-共享内存
- 进程间通信----共享内存
- 进程间通信---共享内存
- ios NSString 去除首尾和中间空格(亲测可用)
- Linux环境进程间通信(一):管道及有名管道
- 多线程编程
- Linux内核很吊之 module_init解析 (下)
- Linux网络编程:原始套接字的魔力【上】
- 进程间通信---共享内存
- E: 软件包 atom 需要重新安装,但是我无法找到相应的安装文件。
- Ubuntu安装磁共振处理软件Fsl步骤
- 进程间通信--信号(进程间通信唯一的异步方式)
- linux 进程(二) --- 进程的创建及相关api
- linux 标准IO缓冲机制探究
- 进程间同步---system v ipc 对象信号灯集
- Linux 原始套接字--myping的实现
- u-boot启动完全分析
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
途龙
途帮
建行友途车主卡
途友网
途友
威途x35
途威
诺基亚威途
大众途威
途威车的价位和图片
途威价格
途安l
途安l2019
途安l2018款
途安海外
touran途安
途安论坛
途安7座
进口途安
大众途安7座
途安l六座版
途安怎么样
途安l论坛
途安油耗
7座途安
2016途安
途安l价格
途安l怎么样
途安七座
途安和途安l区别
大众tu途安
途安价格
新途安l
途安改装
途安2016
途安商务车
途安l7座
2015款途安
二手途安
途安l试驾
途安1.8t