共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程地址空间,这些进程间数据传递将不在涉及到内核,但任何事都有二义性,它是一个临界资源,但这样的方法却没有给提供任何保护。
如图:
将共享区的代码通过页表映射到不同的PCB下,就可以实现共享内存,
以下为系统调用:
int shmget(key_t key,size_t size,int shflg); //创建共享内存
void* shmat(int shmid,const char* shmaddr,int shmflg); //映射关系
参数:
shmid:共享内存标识符
shmaddr:指定要连接的地址,为NULL时,自动选择一个地址
shmflg:设置共享内存特性,一般为0
返回值:成功返回一个指向共享内存的指针,失败返回-1
int shmdt(const char* shmaddr); //断开映射关系
int shmctl(int shmid,int cmd,struct shmid_da* buf); //控制共享内存
以下是代码实现:
comm.h
#pragma once
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
int createShm(int size);
int destoryShm(int shmid);
int getShm(int size);
comm.c
#include<stdio.h>
#include"comm.h"
static int commShm(int size,int flags)
{
key_t k = ftok(PATHNAME,PROJ_ID);
if (k<0)
{
perror("ftok");
return -1;
}
int shmid = 0;
if((shmid = shmget(k,size,flags)) < 0)
{
perror("shmget");
return -2;
}
return shmid;
}
int destoryShm(int shmid)
{
if(shmctl(shmid,IPC_RMID,NULL) < 0)
{
perror("shmctl");
return -1;
}
return 0;
}
int createShm(int size)
{
return commShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int getShm(int size)
{
return commShm(size,IPC_CREAT);
}
server.c
#include<stdio.h>
#include"comm.h"
int main()
{
int shmid = createShm(4096);
char *addr = shmat(shmid,NULL,0);
sleep(2);
int i = 0;
while(i++ < 26)
{
printf("Client# %s\n",addr);
sleep(1);
}
shmdt(addr);
sleep(2);
destoryShm(shmid);
return 0;
}
client.c
#include<stdio.h>
#include"comm.h"
int main()
{
int shmid = getShm(4096);
sleep(1);
char* addr = shmat(shmid,NULL,0);
sleep(2);
int i = 0;
while(i < 26)
{
addr[i] = 'A' +i;
i++;
addr[i] = 0;
sleep(1);
}
shmdt(addr);
sleep(2);
return 0;
}
结果可以自己实验一下,但是和消息队列一样,它的生命周期也是随内核,故需要用
ipcs -m //查看
ipcrm -m//删除 IPC资源