原理图:
通过在物理地址上开辟出一块内存,通过页表建立多个进程的虚拟内存与这块内存的映射,让进程可以访问这块空间,映射一旦建立就相当于进程自己拥有了这块内存。
特点:
通信速度快;
生命周期随内核;
不带任何同步机制,所以常常和信号量一块使用。
共享内存的操作:
创建:
int shmget(key_t key, size_t size, int shmflg);
参数描述:
key:由ftok()生成
size:内存的大小,一般设置为页的整数倍,如果小于页的整数倍则实际大小向上取整
shmflg:IPC_CREAT,表示存在获取,不存在创建;IPC_CREAT|IPC_ESCL,不存在创建,存在出错返回
返回值:
成功返回共享内存标识符,失败返回-1。
删除:
删除一般使用 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:标识一个共享内存
cmd:删除时为IPC_RMID
buf:删除时NULL
返回值:
成功返回0, 失败返回-1。
链接共享内存:
共享内存被创建之后,使用时要进行链接
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:标识一个共享内存
shmaddr:要连接的位置,一般为NULL,这样就交给了操作系统进行处理
shmflg:一般为0
返回值:
成功返回虚拟地址
取链接共享内存:
int shmdt(const void *shmaddr);
参数:
shmaddr:链接内存时返回的虚拟地址
返回值:
成功返回0,失败返回-1
实例代码:
实现父子进程去链接共享内存,子进程写内容,父进程取内容
comm.h
#ifndef _COMM_H_
#define _COMM_H
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define PATHNAME "."
#define PJIO_ID 0x666
int createShm();
int getShm();
int destroy();
#endif
comm.c
#include"comm.h"
static int commShm(int flags)
{
//生成一个key值,用来创建共享内存
key_t key = ftok(PATHNAME, PJIO_ID);
if(key < 0)
{
perror("ftok");
return -1;
}
//创建共享内存,按照flags形式创建
int shmid = shmget(key, 4096, flags);
if(shmid < 0)
{
perror("shmid");
return -2;
}
return shmid;
}
int createShm()
{
//创建
return commShm(IPC_CREAT|IPC_EXCL|0666);
}
int getShm()
{
//获取
return commShm(IPC_CREAT);
}
int destroy(int shmid)
{
//销毁
if(shmctl(shmid, IPC_RMID,NULL)<0)
{
return -1;
}
return 0;
}
myshm.c
#include"comm.h"
int main()
{
//创建共享内存
int shmid = createShm();
//创建子进程
pid_t id = fork();
if(id == 0)//子进程
{
//子进程连接共享内存
char *shm = shmat(shmid, NULL, 0);
int i = 0;
while(i < 26)
{
//每隔一秒写入一个字符
shm[i] = 'A'+i;
i++;
sleep(1);
}
shm[i] = '\0';
//取消于共享内存的连接
shmdt(shm);
}
else//父进程
{
//连接共享内存
char *shm = shmat(shmid, NULL, 0);
int i = 0;
while(i<26)
{
//每隔一秒,将内存中的数据当作字符串进行访问
sleep(1);
printf("%s\n", shm);
i++;
}
//取消与共享内存的连接
shmdt(shm);
//回收子进程
wait(NULL);
//销毁共享内存
destroy(shmid);
}
return 0;
}
运行结果: