shared memory有两一种,一种是更老的但是兼容性更好的 System V shared memory。一种是POSIX shared memory。
man shm_overview 可以查看POSIX shared memory的介绍。
接口
#include <sys/ipc.h>
#include <sys/shm.h>
key_t ftok(const char *pathname, int proj_id);
int shmget(key_t key, size_t size, int shmflg);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
system v 的ipc,使用key来标识一个ipc。key相同,那创建或者获取的就是同一个ipc。
为了得到一个key。提供了ftok()接口,传入一个文件路径和project id返回一个key。当文件和project id相同时,返回的key就相同。
project id使用低8位,同时手册说如果project id为0,那行为是未定义的,但是测试是可以为0的。
Today, proj_id is an int, but still only 8 bits are used.
Typical usage has an ASCII character proj_id, that is why the behavior is said to be undefined when proj_id is zero.
测试key的结果:
key = ftok("test.c", 0);
key = ftok("test.c", 1);
sizeof(key)等于4,说明key是一个32位整数。
上述2行代码,得到的key分别为:0x2c498 和 0x102c498。test.c的inode为0x40c498。device为:Device: 802h/2050d,即0x802。
所以可以推断key的构造方法:
高8位:project id的低8位。
接下来8位:device的低8位。
低16位:inode的低16位。
创建一个新的share memory,或者获得一个新的share memory。返回 the identifier of the System V shared memory segment。
注意这个id不是文件描述符,不能也不需要使用close关闭。
当使用shmctl删除一个share memory,且所有的使用者都shmdt后,这个share memory就被内核释放了。不需要像fd一样close。
第一个参数key,通常使用ftok获得,当然你也可以有自己的策略,只要保证key唯一即可。
第二个参数size,是要创建的shared memory segment的大小,如果不创建,这个参数不被使用,可以传入0。
大小向上对齐到PAGE_SIZE。(rounded up to a multiple of PAGE_SIZE)。
第三个参数shmflg:
IPC_CREAT 创建新的segment。
IPC_EXCL 和IPC_CREAT配合使用,如果segment已经存在,那么返回失败。
shmflg的低9位用来指定权限和linux系统的文件权限一样。所以创建的时候,一定要指定权限,否则shmat会提示没有权限:
IPC_CREAT|IPC_EXCL|0644
将share memory绑定到一个地址,这样就可以通过这个地址读写共享内存了。
attaches the System V shared memory segment identified by shmid to the address space of the calling process。
第一个参数是shmid,使用shmget获得。
第二个参数shmaddr,是地址,指示如何分配地址。
如果为NULL,则系统选择一个未使用的,对齐到page的地址。
第三个参数是 shmflg,可以为 SHM_RND等。
shmat的反向操作,传入shmat的返回值。解绑share memory
detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
控制一个shared memory。可以获得信息、删除shared memory。这里主要用的是删除shared memory。
shmctl(shmfd, IPC_RMID, NULL)
删除可以在shmdt之前,如果删除的时候,还有用户attach了,那么系统不会删除,等最后一个用户shmdt的时候,才会删除。
参考:
https://stackoverflow.com/questions/26120212/implementing-shared-memory-without-root-privilege