共享内存是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 ;
}
运行结果: