共享内存是UNIX提供的进程间通信手段中速度最快的一种,也是最快的IPC形式。为什么是最快的呢,因为数据不需要在客户进程和服务器进程之间复制,所以是最快的一种IPC。这是虚存中由多个进程共享的一个公共内存块。
两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
如果服务器进程正在将数据放入到共享存储区,则在它做完这一操作之前,客户进程不应当去取这些数据。通常信号量用于同步共享存储访问。
由于共享内存是通过映射到同一块物理内存后进行的通信,因此肯定需要映射到内存的函数和解除映射的函数,主要有以下几种
#define SHMAT 21//空间映射:把上面打开的内存区域连接到用户的进程空间中
#define SHMDT 22//解除映射:将共享内存从当前进程中分离
#define SHMGET 23//创建打开一个内存区域
#define SHMCTL 24//内存区域的控制:包括初始化和删除内存区域。
注意:共享内存通信本身没有提供同步机制,如果同时被多个进程进行映射和写操作,会导致破坏该内存空间的内容。因此在实际应用过程中,需要通过其他的机制来同步对共享内存的访问。比如信号量。
内核为每个共享存储段维护着一个结构,该结构至少要为每个共享存储段包含以下成员:
struct shmid_ds
{
struct ipc_perm shm_perm;
size_t shm_segsz;
pid_t shm_lpid;
pid_t shm_cpid;
shmatt_t shm_nattch;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
};
1.调用的第一个函数为shmget:
#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
2.shmctl函数对共享内存段执行多种操作
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
3.一旦创建了共享存储段,进程就可调用shmat将其连接到它的地址空间中。
void *shmat(int shmid,const void* addr,int flag);
int shmdt(const void* addr);
具体代码实现:
#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 0X6667
int CreateShm(int size);
int GetShm(int size);
int destroyShm(int shmid);
#endif //_COMM_H_
#include"comm.h"
int CommShm(int size,int flags)
{
key_t key = ftok(PATHNAME,PROJ_ID);
if(key < 0)
{
perror("ftok");
return -1;
}
int shmid = shmget(key,size,flags);
if(shmid < 0)
{
perror("shmget");
return -2;
}
return shmid;
}
int CreateShm(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;
}
#include"comm.h"
int main()
{
int shmid = CreateShm(4096);
char *addr = shmat(shmid,NULL,0);
if(addr == NULL)
{
return 1;
}
int i = 0;
char s = 'a';
while(1)
{
addr[i] = s;
s++;
}
addr[i] = 0;
sleep(4);
shmdt(addr);
printf("shm quit!\n");
return 0;
}
//client.c
int main()
{
int shmid = GetShm(4096);
//printf("hello client!\n");
char *addr = shmat(shmid,NULL,0);
if(addr == NULL)
return 2;
printf("%s",addr);
sleep(10);
shmdt(addr);
printf("shm quit!\n");
return 0;
}
运行结果: