共享内存就是在内核空间中开辟一块区域用来进程间共享访问来达到进程间通信的目的.和管道类似,也分为亲缘进程间通信和普通进程间通信两种.但是只是在创建shmid的时候使用key不同而已,而且和管道不同的是,共享内存的读取可以重复无数次,而管道不能重复读取,读取一次以后管道中将没有数据.
如果是普通进程自己的通信,需要一个key避免共享内存重合.key的生成建议是用ftok函数进行生成,相同的key指向的共享内存空间相同,两个进程使用相同的key就可以使用同一块共享内存空间了.
#include <sys/types.h>
#include <sys/ipc.h>
ket_t ftok(char * fname, int id);//fname 已经存在的文件名 id 子序列号
返回值为int型的key.
接着分配或者得到共享内存并得到共享内存标识符
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);//key就是上面生成的(亲缘进程为0),size为共享内存的大小
//shmflg操作标识,0:取共享内存标识符,若不存在则函数会报错,IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符,IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错.
返回值 -1出错,成功返回shmid(共享内存标识符)
得到共享内存标识符以后一般还要将在内核空间中的共享内存映射到用户空间去,方便操作.
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);//shmid,之前获取到的共享内存标识符,shmaddr:映射到用户空间的地址,shmflg:操作,默认为0,读写操作,SHM_RDONLY:为只读模式;
获取到了映射的以后的地址,我们就可以像操作malloc函数获得到的内存一样进行读写操作来进行通信了.
写数据:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <string.h> int main(int argc,char *argv[]){ int key = 0; char *memery = NULL; int shmid = 0; key = ftok("./",0); shmid = shmget(key,1024,IPC_CREAT | 0666);//创建和设置共享内存 if(shmid > 0){ printf("shared menery succeed "); }else{ printf("creat failed "); return -1; } memery = (char *)shmat(shmid,NULL,0);//得到映射以后的地址 if((void *)memery == (void *)-1){ printf("get the addr failed "); shmctl(shmid,IPC_RMID,NULL);//出错以后关闭内核共享内存 return -2; } strcpy(memery,"hello shared memery");//将数据写了入共享内存 sleep(20);//等待其他进程读取数据 shmdt((void *)memery);//删除映射 shmctl(shmid,IPC_RMID,NULL);//关闭内核的共享内存 return 0; }
读数据:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <string.h> int main(int argc,char *argv[]){ int key = 0; char *memery = NULL; int shmid = 0; key = ftok("sig.c",0); shmid = shmget(key,1024,IPC_CREAT | 0666); if(shmid > 0){ printf("shared menery succeed "); }else{ printf("creat failed "); return -1; } memery = (char *)shmat(shmid,NULL,0); if((void *)memery == (void *)-1){ printf("get the addr failed "); shmctl(shmid,IPC_RMID,NULL); return -2; } //上面的代码和写操作是一样的,都是要获取到共享内存的映射到用户空间的地址 sleep(2);//等待其他进程写数据 printf("%s ",memery);//打印内容 shmdt((void *)memery); shmctl(shmid,IPC_RMID,NULL); return 0; }