共享内存能够说是最有用的进程间通讯方式,也是最快的IPC形式。是针对其余通讯机制运行效率较低而设计的。两个不一样进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A能够即时看到进程B对共享内存中数据的更新,反之亦然。因为多个进程共享同一块内存区域,必然须要某种同步机制,互斥锁和信号量均可以。node
采用共享内存通讯的一个显而易见的好处是效率高,由于进程能够直接读写内存,而不须要任何数据的拷贝。对于像管道和消息队列等通讯方式,则须要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另外一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不老是读写少许数据后就解除映射,有新的通讯时,再从新创建共享内存区域。而是保持共享区域,直到通讯完毕为止,这样,数据内容一直保存在共享内存中,并无写回文件。共享内存中的内容每每是在解除映射时才写回文件的。所以,采用共享内存的通讯方式效率是很是高的。数组
进程间须要共享的数据被放在一个叫作IPC共享内存区域的地方,全部须要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。系统V共享内存经过shmget得到或建立一个IPC共享内存区域,并返回相应的标识符。内核在保证shmget得到或建立一个共享内存区,初始化该共享内存区相应的shmid_kernel结构体的同时,还将在特殊文件系统shm中,建立并打开一个同名文件,并在内存中创建起该文件的相应dentry及inode结构,新打开的文件不属于任何一个进程(任何进程均可以访问该共享内存区)。全部这一切都是系统调用shmget完成的。数据结构
注:每个共享内存区都有一个控制结构struct shmid_kernel,shmid_kernel是共享内存区域中很是重要的一个数据结构,它是存储管理和文件系统结合起来的桥梁,定义以下:ide
struct shmid_kernel /* private to the kernel */ { struct kern_ipc_perm shm_perm; /* operation permission structure */ struct file *shm_file; /* pointer in kernel */ unsigned long shm_nattch; /* number of current attaches */ unsigned long shm_segsz; /* size of segment in bytes */ time_t shm_atim; /* last-attach time */ time_t shm_dtim; /* last-detach time */ time_t shm_ctim; /* last-change time */ pid_t shm_cprid; /* pid of creator */ pid_t shm_lprid; /* pid of last shmop() */ };
正如消息队列和信号灯同样,内核经过数据结构struct ipc_ids shm_ids维护系统中的全部共享内存区域。上图中的shm_ids.entries变量指向一个ipc_id结构数组,而每一个ipc_id结构数组中有个指向kern_ipc_perm结构的指针。到这里读者应该很熟悉了,对于系统V共享内存区来讲,kern_ipc_perm的宿主是 shmid_kernel结构,shmid_kernel是用来描述一个共享内存区域的,这样内核就可以控制系统中全部的共享区域。同时,在 shmid_kernel结构的file类型指针shm_file指向文件系统shm中相应的文件,这样,共享内存区域就与shm文件系统中的文件对应起来。spa
在建立了一个共享内存区域后,还要将它映射到进程地址空间,系统调用shmat()完成此项功能。因为在调用shmget()时,已经建立了文件系统 shm中的一个同名文件与共享内存区域相对应,所以,调用shmat()的过程至关于映射文件系统shm中的同名文件过程,原理与mmap()大同小异。设计
头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
shmget()用来得到共享内存区域的ID,若是不存在指定的共享区域就建立相应的区域。shmat()把共享内存区域映射到调用进程的地址空间中去,这样,进程就能够方便地对共享区域进行访问操做。shmdt()调用用来解除进程对共享内存区域的映射。shmctl实现对共享内存区域的控制操做。指针
在/proc/sys/kernel/目录下,记录着系统V共享内存的一下限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,能够手工对其调整,但不推荐这样作。code
/***** testwrite.c *******/ #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct{ char name[4]; int age; } people; main(int argc, char** argv) { int shm_id,i; key_t key; char temp; people *p_map; char* name = "/dev/shm/myshm2"; key = ftok(name,0); if(key==-1) perror("ftok error"); shm_id=shmget(key,4096,IPC_CREAT); if(shm_id==-1) { perror("shmget error"); return; } p_map=(people*)shmat(shm_id,NULL,0); temp='a'; for(i = 0;i<10;i++) { temp+=1; memcpy((*(p_map+i)).name,&temp,1); (*(p_map+i)).age=20+i; } if(shmdt(p_map)==-1) perror(" detach error "); } /********** testread.c ************/ #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct{ char name[4]; int age; } people; main(int argc, char** argv) { int shm_id,i; key_t key; people *p_map; char* name = "/dev/shm/myshm2"; key = ftok(name,0); if(key == -1) perror("ftok error"); shm_id = shmget(key,4096,IPC_CREAT); if(shm_id == -1) { perror("shmget error"); return; } p_map = (people*)shmat(shm_id,NULL,0); for(i = 0;i<10;i++) { printf( "name:%s\n",(*(p_map+i)).name ); printf( "age %d\n",(*(p_map+i)).age ); } if(shmdt(p_map) == -1) perror(" detach error "); }