共享内存是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间。这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
共享内存没有任何的同步与互斥机制,所以要使用信号量来实现对共享内存的存取的同步。
如上图,所谓共享内存,把进程的虚拟地址中的某一块通过页表的数据结构映射到共同的物理内存上,若有两个进程,假设通过进程1修改内存内容,进程2可以看到,因为本质上是同一块空间,实际上这样就完成通信了。
以下是共享内存的相关函数接口:
shmget() 函数:用来创建共享内存
int shmget(key_t key, size_t size, int shmflg);
key:这个共享内存段名字
size:共享内存的大小
shmflg:由9个权限标志组成,他们的用法和创建文件时使用的mode模式标志是一样的
成功返回该共享内存段的标识码,失败返回-1.
shmat()函数:将虚拟内存的某个空间与共享内存建立关联
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:共享内存标识。
shmaddr:指定连接的地址。
shmflg:两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节,失败返回-1。
shmdt()函数:解除关联
int shmdt(const void*shmaddr);
当一个进程不需要共享内存的时候,就需要解除关联。共享内存段与当前进程脱离不等于删除共享内存段。
shmaddr:shmat所返回的指针
返回值:成功返回0,并将shmid_ds结构体中的 shm_nattch计数器减1;失败返回-1。
shmctl()函数:用于控制共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:由shmget返回的共享内存标识码。
cmd:指定的执行操作,设置为IPC_RMID时表示可以删除共享内存。
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0,失败返回-1。
共享内存的实例代码:
Makefile
.PHONY:all
all:server client
client:client.c common.c
gcc -o $@ $^
server:server.c common.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f server client
#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 PROJ_ID 0x6666
int creatShm(int size);
int getShm(int size);
int destroyShm(int shmid);
#endif
comm.c
#include "comm.h"
static int commShm(int size,int flags)
{
key_t _key = ftok(PATHNAME,PROJ_ID);
if(_key < 0)
{
perror("ftok");
return -1;
}
int shmid = 0;
if((shmid = shmget(_key,size,flags)) < 0)
{
perror("shmget");
return -2;
}
return shmid;
}
int creatShm(int size)
{
return commShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int getShm(int size)
{
return commShm(size,IPC_CREAT);
}
int destroyShm(int shmid)
{
if(shmctl(shmid,IPC_RMID,NULL) < 0)
{
perror("shmctl");
return -1;
}
return 0;
}
server.c
#include "comm.h"
int main()
{
int shmid = creatShm(4096);
char *buf = shmat(shmid,NULL,0);
sleep(2);
int i = 0;
while(i++ < 26)
{
printf("client#%s\n",buf);
sleep(1);
}
shmdt(buf);
sleep(2);
destroyShm(shmid);
return 0;
}
client.c
#include "comm.h"
int main()
{
int shmid = getShm();
sleep(1);
char* buf;
buf = shmat(shmid,NULL,0);
sleep(2);
int i = 0;
while(i<26)
{
buf[i]='A'+i;
i++;
buf[i]=0;
sleep(1);
}
shmdt(buf);
sleep(2);
return 0;
}
共享内存小结:
双向通信
用于随意进程
不存在面向字节流或面向数据块的概念
没有同步互斥
生命周期随内核