进程间通信-共享内存

来源:互联网 发布:库里2017年总决赛数据 编辑:程序博客网 时间:2024/06/09 08:16

共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC通信形式。是针对其他通信机制运行效率较低而设计的,往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。

机制如下:


特点:

1.内存共享是进程间通信速度最快的:

由上图可知,内存共享是进程1从其地址空间直接写到物理内存中,进程2则直接通过地址空间虚拟地址从内存中取,不需要通过进入内核来传递消息,而消息队列,信号量则都要在内核开辟一块空间,进程通信传递需从用户区拷贝到内核区,再从内核区拷贝到用户区,所以其不涉及内核的拷贝,所以其效率较高。

2.共享内存不带任何同步、互斥机制,所以其一般都与信号量匹配使用;

3.共享内存开辟在物理内存上,所以其生命周期为随内核。


Linux下共享内存的两条命令:

ipcs   -m  ;           //查看共享内存ipcrm -m  <shmid>;    //删除共享内存


共享内存函数:

1.创建共享内存:

函数:

int shmget(key_t key,size_t size,int shmflag);
参数:

key:共享内存唯一的键值,用ftok()函数获取;

size:申请的内存大小,一般为页的整数倍,因为系统分配的大小始终为页的整数倍,1页=4k;

shmflag:IPC_CREAT(单独使用没有创建共享内存,创建新的共享内存,若有,则返回存在的共享内存),IPC_EXCL(与IPC_CREAT合用,不存在,创建新的,存在返回错误码);

返回值:

成功返回共享内存id,失败返回错误码。


2.删除共享内存:

函数:

int shmctl(int shmid,int cmd,struct shmid_ds* buf);
参数:

shmid:共享内存id;

cmd:删除时设为IPC_IMID;

buf:对共享内存的修改或对其查看,若cmd设为IPC_IMID,则设为NULL;


3.共享内存的挂接:

函数:(此函数用法与malloc()相同)

void* shmat(int shmid,const void* shmaddr,int shmflg);
参数:

shmid:共享内存id;

shmaddr:共享内存与指定虚拟地址建立映射关系,一般设为NULL,即由操作系统安排;

shmflg:一般设为缺省0;

返回值:

建立映射关系后返回的虚拟地址。

4.与共享内存断开联系:

函数:

int shmdt(const void* shmaddr);
参数:

shmaddr:shmat()函数的返回值虚拟地址;

代码实现:

comm.h

#ifndef _COMM_H__#define _COMM_H__#include <stdio.h>#include <sys/ipc.h>#include <sys/shm.h>#include <unistd.h>#define PATH "."#define PROJ_ID 0x6666int creatShm(int size);    //创建 int getShm(int size);     //获取 int destroyShm(int shmid);  //删除 #endif   //_COMM_H__


server.c(读打印)

#include "comm.h"int main(){int shmid=creatShm(4096);   //创建共享内存     //printf("create success!!!  shmid:%d\n",shmid); sleep(3);char* addr=shmat(shmid,NULL,0);  //使当前进程与共享内存挂接 ,此函数返回进程虚拟地址 int i=0;                         //第二个参数为指定的虚拟地址,一般由操作系统指定,所以设为null while(i<26){printf("%s\n",addr);      //打印地址(读共享内存处内容)处内容    sleep(1);++i;}shmdt(addr);    //使当前进程与共享内存断开关联 int ret=destroyShm(shmid);//printf("destroy success. ret:%d\n",ret);return 0;}

client.c(写)

#include "comm.h"int main(){int shmid=getShm(4096);   //获取已创建好的共享内存 printf("getShm success!!  shmid:%d\n",shmid);char* addr=shmat(shmid,NULL,0);    //使当前进程与共享内存挂接 ,此函数返回进程虚拟地址 int i=0;while(i<26){addr[i]='A'+i;   //向共性内存处写内容 sleep(1);++i;addr[i]=0;}shmdt(addr);    //使当前进程与共享内存断开关联return 0;}
comm.c

#include "comm.h"static int commShm(int size,int flags)   {key_t _key=ftok(PATH,PROJ_ID);if(_key<0){perror("ftok");return -1;}int shmid=shmget(_key,size,flags);  //创建或获取共享内存 参数size为页的整数倍(会自动调整)  1页=4kif(shmid<0){perror("shmget");return -2;}return shmid;}int creatShm(int size){return commShm(size,IPC_CREAT|IPC_EXCL|0666);}int getShm(int size){return commShm(size,IPC_CREAT);}int destroyShm(int shmid){if(shmctl(shmid,IPC_RMID,NULL)<0)  //立即删除shmid标识的共享内存 {perror("destroy:shmctl");return -1;}return 0;}


效果如下: