Share memory允许多个进程共享一个给定的存储区域,因为数据不需要在多个进程之间复制,所以他是最快的IPC。要注意的是多个进程在访问share memory的时候一定要做同步机制,防止读到脏数据,或者写坏数据。
API介绍-
1.shmget
sys/shm.h
int shmget(key_t key, size_t size, intflag);
成功执行返回share memory id,若出错返回-1
参数key通过ftok获得
参数size表示共享存储空间的长度,以字节为单位。实现通常将其向上取为系统页长的整数倍,页对齐,若时间长度并不是页的整数倍,最后一个页的剩余部分不可用。
如果进程创建share memory,则必须指定size的大小;
如果进程只是访问share memroy,指定size为0;
参数flag,定义一些访问权限
IPC_CREAT| IPC_EXCL 表示share memory id标识的共享存储是否已经存在,存在的话就会返回-1,并且errno=EEXIST;
-
2.shmat
sys/shm.h
int shmat(int shmid, const char *addr, int flag);
成功时返回映射出来的地址,失败时返回-1
参数shmid是通过shmget得到的
参数addr 如果为0,表示shm连接到有内核选择的第一个可用的地址上。
如果非0,并且flag也没有执行SHM_RND,则连接上addr指定的地址上;
如果非0,并且flag指定了SHM_RND,则连接到(addr-(addr mod SHMLBA))所表示的地址上;
参数flag,SHM_RDONLY表示只读,否则表示读写。
-
3.shmdt
sys/shm.h
int shmdt(const char *addr);
成功时返回0,失败时返回-1
参数addr 是shmat的返回值。相当于一个detach的动作,减少shmid_ds中的shm_nattch数目
-
4.shmctl
sys/shm.h
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
成功时返回0,失败时返回-1
参数shmid通过shmget获得
参数cmd:IPC_STAT,获取shmid_ds机构体中的数据信息
IPC_SET,设置shmid_ds 结构体中的信息给SHM
IPC_RMID,删除shm
SHM_LOCK和SHM_UNLOCK,这两个标志容易搞混,它并不是说对shm加锁,做进程同步,真正的意义在于锁定这块共享内存并禁止它交换。被锁定的区段不允许被交换出内存(否则它可能被交换到虚拟内存中,swap分区)。这样做的优势在于,与其把内存区段交换到文件系统,在某个应用程序调用时再交换回内存,不如让它一直处于内存中,且对多个应用程序可见。从提升性能的角度来看,很重要的。但是,这并不代表一个进程锁定住共享内存以后其它进程禁止访问。锁定后只是不会交换到文件系统里(虚拟内存,swap分区),而不是指它的访问性
参数buf,具体根据cmd来输入,或者传入NULL
sample code:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_PATH "./this_key"
typedef struct {
int a;
int b;
int c;
int e;
int d;
}INFO;
int server()
{
int shmid = shmget(ftok(SHM_PATH, 0x05), sizeof(INFO), IPC_CREAT | 0666);
printf("shmid = %d\n", shmid);
printf("shmsize = %d\n", sizeof(INFO));
struct shmid_ds ds;
shmctl(shmid, IPC_STAT, &ds);
printf("realsize = %d\n", ds.shm_segsz);
printf("attch num %d\n", ds.shm_nattch);
INFO share_info;
share_info.a = 1;
share_info.b = 1;
share_info.c = 0;
share_info.d = 2;
share_info.e = 0;
INFO *ptr = (INFO *)shmat(shmid, 0, 0);
memcpy(ptr, &share_info, sizeof(INFO));
sleep(20);
shmctl(shmid, IPC_RMID, NULL);
printf("share memory removed\n");
}
int client()
{
int shmid = shmget(ftok(SHM_PATH, 0x05), 0, IPC_CREAT | 0666);
struct shmid_ds ds;
shmctl(shmid, IPC_STAT, &ds);
printf("\trealsize = %d\n", ds.shm_segsz);
printf("\tattch num %d\n", ds.shm_nattch);
INFO *p_share_info;
p_share_info = (INFO *)shmat(shmid, 0, 0);
printf("\tget info is %d %d %d %d %d\n",
p_share_info->a,
p_share_info->b,
p_share_info->c,
p_share_info->d,
p_share_info->e);
shmdt(p_share_info);
}
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid == 0) {
sleep(1);
client();
} else if (pid > 0) {
server();
}
}