接下来总结进程间通讯的另外一种方式----共享内存。
1、概念
共享内存是一种最为高效的进程间通信方式,指两个或多个进程共享一个给定的存储区。它通过内核对象将进程中的虚拟地址映射到相同的物理内存上,因此系统分配共享内存是按照"页"为单位。
2、特点
-
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
-
因为多个进程可以同时操作,所以需要进行同步。
-
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
3、函数原型
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);// 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);// 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
int shmdt(void *addr); // 断开与共享内存的连接:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);// 控制共享内存的相关信息:成功返回0,失败返回-1
需要注意的是:
当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。
当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。
4、模拟共享内存
我们用server来创建共享存储段,用client获取共享存储段的标识符,二者关联起来之后server将数据写入共享存储段,client从共享区读取数据。通信结束之后server与client断开与共享区的关联,并由server释放共享存储段。
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 CreateShm(int size);
int DestroyShm(int shmid);
int GetShm(int size);
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 DestroyShm(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"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);
DestroyShm(shmid);
return 0;
}
client.c
#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;
}
5、总结:
(1)优点:使用共享内存进行进程之间的通信是非常方便的,数据的共享还使进程间的数据不用传送,而是直接访问内存,加快了程序的效率。
(2)缺点:共享内存没有提供同步机制,多个进程共享同一块物理内存空间,则进程访问时必须为互斥访问,必须通过同步机制(信号量)来进行控制。