POSIX共享内存概述
共享内存是最高效的IPC机制,因为它不涉及进程之间的任何数据传输。
这种高效率带来的问题是,我们必须用其他辅助手段来同步进程对共享内存的访问,否则会产生竞态条件。
因此,共享内存通常和其他进程间通信方式一起使用。
Linux下有三种共享内存的IPC技术:System V共享内存、共享文件映射(mmap)、POSIX共享内存。 本文只介绍POSIX共享内存。POSIX共享内存和POSIX消息队列,有名信号量一样都是具有随内核持续性的特点。
POSIX共享内存流程
- 指定一个名字参数调用shm_open,以创建一个新的共享内存区对象或打开一个已存在的共享内存区对象.
- 调用mmap把这个共享内存区映射到调用进程的地址空间.
和内存映射文件进行通信的使用上差别在于mmap描述符参数获取方式不一样
如下图所示:
POSIX共享内存相关接口
#include <sys/mman.h> int shm_open(const char *name, int oflag, mode_t mode);//成功返回非负的描述符,失败返回-1
参数:
name:POSIX IPC的名字,前面关于POSIX进程间通信都已讲过关于POSIX IPC的规则,这里不再赘述。
oflag:操作标志,包含:O_RDONLY,O_RDWR,O_CREAT,O_EXCL,O_TRUNC。其中O_RDONLY和O_RDWR标志必须且仅能存在一项。
mode:用于设置创建的共享内存区对象的权限属性。和open以及其他POSIX IPC的xxx_open函数不同的是,该参数必须一直存在,如果oflag参数中没有O_CREAT标志,该位可以置0;
注意:
这里的name不能写成/tmp/aaa.sem这样的格式,因为在linux下,sem都是创建在/dev/shm目录下。
你可以将name写成“/mysem”或“mysem”,创建出来的文件都是“/dev/shm/sem.mysem”,千万不要写路径。也千万不要写“/tmp/mysem”之类的。
返回值:
若成功,返回指向信号量的指针。
若失败,返回SEM_FAILED。
int shm_unlink(const char *name); //shm_unlink用于删除一个共享内存区对象,跟其他文件的unlink以及其他POSIX IPC的删除操作一样,对象的析构会到对该对象的所有引用全部关闭才会发生。
参数:
name: 共享内存区对象的名字
返回值:
若成功,返回0。
若失败,返回-1。
POSIX共享内存使用例程
int shm_fd = 0; char * shm_data = NULL; char shm_buf[1024]={0}; shm_fd = shm_open("shm-update", O_CREAT|O_RDWR, 0777); if (shm_fd < 0) { perror("fail to shm_open"); } else { //调整确定文件共享内存的空间 ftruncate(shm_fd, 1024); if(ftruncate(shm_fd, 1024)== -1) { perror("ftruncate shm_fd failed"); } //映射目标文件的存储区 shm_data = mmap(NULL,1024, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, SEEK_SET); if(NULL == shm_data) { perror("fail to mmap"); } } shm_buf[0]='1'; memcpy(shm_data,shm_buf,sizeof(shm_buf));
int shm_fd = 0; char * shm_data = NULL; // char shm_buf[1024]={0}; shm_fd = shm_open("shm-update", O_RDWR, 0777); if (shm_fd < 0) { perror("fail to shm_open"); } else { //调整确定文件共享内存的空间 ftruncate(shm_fd, 1024); if(ftruncate(shm_fd, 1024)== -1) { perror("fail to ftruncate"); } //映射目标文件的存储区 shm_data = mmap(NULL,1024, PROT_READ, MAP_SHARED, shm_fd, SEEK_SET); if(NULL == shm_data) { perror("fail to mmap"); } } printf("shm_buf:%s-%d",shm_data,*shm_data);