共享内存


进程间通信的本质是让不同的进程访问一块公共的资源。

1、共享内存是进程间通信最快的方式(为什么)

2、共享内存不提供任何的同步与互斥关系。(由用户维护,可以用信号量)

以下图解释了问题1,原因是,由于共享内存的机制,两个进程不需要拷贝拷贝数据,这个特点可能在数据较少的情况下看不出来,但是数据较多时,优势较为明显。

下图是shmat之前之后的共享内存示意图:(shmget获得共享内存后需要挂接)


函数:

用于Linux进程通信共享内存。共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。

shmat(把共享内存区对象映射到调用进程的地址空间)

void*shmat(intshmid,constvoid*shmaddr,intshmflg)

参数:

shmid共享内存标识符shmaddr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置shmflg如果设置为SHM_RDONLY是只读模式,其他为读写模式

返回值:成功返回附加好的共享内存地址

shmdt(断开共享内存连接)

intshmdt(constvoid*shmaddr)

参数:

shmaddr:连接的共享内存的起始地址

返回值:成功返回0

shmget(得到一个共享内存标识符或创建一个共享内存对象)

intshmget(key_tkey,size_tsize,intshmflg)

参数:

key大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值size大于0的整数:新建的共享内存大小,以字节为单位flags有IPC_CREAT和IPC_EXCL(用法同前面写的一致)

返回值:成功返回共享内存标示符

注:system V分配内存的方法以页为基本单位,一般以页的整数倍分配。

shmctl完成对共享内存的控制

intshmctl(intshmid,intcmd,structshmid_ds*buf)

参数:


shmid

共享内存标识符

cmdIPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内IPC_RMID:删除这片共享内存buf
共享内存管理结构体。具体说明参见共享内存内核结构定义部分

共享内存实现通信的例子

comm.h

#pragmaonce#include<errno.h>#include<sys/ipc.h>#include<sys/shm.h>#include<string.h>#define_PATH_NAME_"/temp"#define_PROJ_ID_0x6666intcreate_shm(intsize);intget_shm();intdestory_shm(intshm_id);void*shm_at(intshm_id);intshm_dt(void*shmaddr);

comm.c

#include"comm.h"staticintcomm_create_shm(intsize,intflags){key_t_key=ftok(_PATH_NAME_,_PROJ_ID_);if(_key<0){perror("ftok");return-1;}//intshm_id=shmget(_key,size,IPC_CREAT|IPC_EXCL);intshm_id=shmget(_key,size,flags);if(shm_id<0){perror("shmget");return-2;}returnshm_id;}intcreate_shm(intsize){intflags=IPC_CREAT|IPC_EXCL|0666;returncomm_create_shm(size,flags);}intget_shm(){intflags=IPC_CREAT;returncomm_create_shm(0,flags);}intdestory_shm(intshm_id){if(shmctl(shm_id,IPC_RMID,NULL)<0){perror("shmctl");return-1;}return0;}void*shm_at(intshm_id){returnshmat(shm_id,NULL,0);}intshm_dt(void*shmaddr){returnshmdt(shmaddr);}

server.c

#include"comm.c"intmain(){intshm_id=create_shm(4096);sleep(5);char*buf=(char*)shm_at(shm_id);sleep(1);sleep(1);while(1){printf("%s\n",buf);sleep(1);if(strcmp(buf,"AAAAA")==0){break;}}shm_dt(buf);sleep(5);destory_sem(sem_id);return0;}

client.c

#include"comm.c"intmain(){intshm_id=get_shm();char*buf=(char*)shm_at(shm_id);intindex=0;while(1){buf[index++]='A';buf[index]='\0';sleep(1);if(index>5){break;}}sleep(5);shm_dt(buf);sleep(5);return0;}