Posix共享内存涉及以下两个步骤:
1、指定一个名字参数调用shm_open,以创建以一个新的共享内存区对象或打开一个已存在的共享内存区对象。
2、调用mmap把这个共享内存区映射到调用进程的地址空间。
头文件:
#include<sys/mman.h>
#include<sys/stat.h>
#include<fcntl.h>
int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);
Link with -lrt(要注意连接这个库)
oflag参数是O_CRTEA|O_RDWR等标志;
mode参数指定权限位如果没有指定O_CREAT标志,那么该参数可以指定为0。(如果是创建的话权限要给够,平常是0644的权限,否则别的进程可能没有权限)。
一般创建的文件是自动放在/dev/shm/的目录下的。
新创建的文件大小一般为0,所以mmap函数调用文件标识符的时候会出错,这时候要用ftruncate()函数扩大文件
#include<unistd.h>
int ftruncate(int fd,off_t length); 成功返回0,出错返回-1
对于一个普通文件:如果该文件的大小大于length参数,额外的数据就会被丢掉。
对于一个共享内存区对象:把该对象的大小设置成length字节。
当打开一个已存在的共享内存对象时,我们可以调用fstat来获取有关该对象的信息。
#include<sys/types.h>
#include<sys/stat.h>
int fstat(int fd, struct stat *buf);
stat结构有12个或以上的成员, 但当fd指代一个共享内存区对象时,只有四个成员含有信息。
struct stat{
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
};
调用时不用定义这个结构体,直接实例化就行了,如:struct stat sta;
下面是两个例子,一个是向共享内存里写,一个读取;
read:
#include<stdio.h> #include<unistd.h> #include<sys/mman.h> #include<fcntl.h> #include<string.h> #include<sys/stat.h> int main(int argc,char* argv[]) { int fd = shm_open(argv[1],O_RDONLY,0); void* buf = NULL; if((buf = mmap(NULL,BUFSIZ,PROT_READ,MAP_SHARED,fd,0)) ==MAP_FAILED ){ perror("mmap error\n"); return 1; } sleep(1); while(1){ printf("read:%s\n",buf); sleep(3); } munmap(buf,BUFSIZ); close(fd); }
执行:./read mmap.txt
write:
#include<stdio.h> #include<unistd.h> #include<sys/mman.h> #include<fcntl.h> #include<string.h> #include<sys/stat.h> int main(int argc,char* argv[]) { int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644); if(fd == -1){ perror("shm_open error\n"); return 1; } ftruncate(fd,100); void* buf = NULL; if((buf = mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0))== MAP_FAILED){ perror("mmap error\n"); return 1; } int i; for(i=2;i<argc;i++){ strcpy(buf,argv[i]); sleep(3); } munmap(buf,BUFSIZ); close(fd); }
执行:
./write mmap.txt aaa bbb ccc