1.什么是共享内存?
共享内存就是允许两个或多个进程共享一定的存储区。就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。因为数据不需要在客户机和服务器端之间复制,数据直接写到内存,不用若干次数据拷贝,所以这是最快的一种IPC。
注:共享内存没有任何的同步与互斥机制,所以要使用信号量来实现对共享内存的存取的同步。
2.与共享内存有关的数据结构
system V版本的通信方式都具有相似的数据结构,参考见:
进程间通信方式——消息队列
注:其中的同只是将数据结构中的消息队列msg换成shm而已
3.与共享内存有关的函数
所有的函数共用头文件
代码语言:javascript复制#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
3.1创建共享内存——>shmget() 函数
代码语言:javascript复制int shmget(key_t key, size_t size, int shmflg);
//成功返回共享内存的ID,出错返回-1
(1)第一个参数key是长整型(唯一非零),系统建立IPC通讯 ( 消息队列、 信号量和 共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到,由内核变成标识符,要想让两个进程看到同一个信号集,只需设置key值不变就可以。
(2)第二个参数size指定共享内存的大小,它的值一般为一页大小的整数倍(未到一页,操作系统向上对齐到一页,但是用户实际能使用只有自己所申请的大小)。
(3)第三个参数shmflg是一组标志,创建一个新的共享内存,将shmflg 设置了IPC_CREAT标志后,共享内存存在就打开。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。一般我们会还或上一个文件权限
3.2操作共享内存———>shmctl()函数
代码语言:javascript复制int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
//成功返回0,出错返回-1
(1)第一个参数,shm_id是shmget函数返回的共享内存标识符。
(2)第二个参数,cmd是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
(3)第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。 shmid_ds结构至少包括以下成员
代码语言:javascript复制struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
3.3挂接操作———>shmat()函数
创建共享存储段之后,将进程连接到它的地址空间
代码语言:javascript复制void *shmat(int shm_id, const void *shm_addr, int shmflg);
//成功返回指向共享存储段的指针,出错返回-1
(1)第一个参数,shm_id是由shmget函数返回的共享内存标识。
(2)第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
(3)第三个参数,shm_flg是一组标志位,通常为0
3.4分离操作———>shmdt()函数
该操作不从系统中删除标识符和其数据结构,要显示调用shmctl(带命令IPC_RMID)才能删除它
代码语言:javascript复制int shmdt(const void *shmaddr); //成功返回0,出错返回-1
(1)addr参数是以前调用shmat时的返回值
4.模拟实现进程间的通信方式———>共享内存
Server作为发送方,每次向共享内存中,写入A,Client作为接收方,每次读取共享内存中的数据
comm.h
代码语言:javascript复制#ifndef __COMM_H__
#define __COMM_H__
#include <stdio.h>
#include <error.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PATHNAME "."
#define PROJ_ID 066
int CreatShmid(int size);
int GetShmid(int size);
int Destory(int shmid);
#endif
comm.c
代码语言:javascript复制#include "comm.h"
static int commShmid(int size,int flag)
{
key_t key=ftok(PATHNAME,PROJ_ID);
if(key>0)
{
return shmget(key,size,flag);
}
else
{
perror("ftok");
return -1;
}
}
int CreatShmid(int size)
{
return commShmid(size,IPC_CREAT|IPC_EXCL|0666);
}
int GetShmid(int size)
{
return commShmid(size,IPC_CREAT);
}
int Destory(int shmid)
{
return shmctl(shmid,0,IPC_RMID);
}
server.c
代码语言:javascript复制#include "comm.h"
int main()
{
int shmid=CreatShmid(4097);
if(shmid>0)
{
int i=0;
char *addr=shmat(shmid,NULL,0);
while(i<20)
{
addr[i ]='A';
addr[i]='#include "comm.h"
int main()
{
int shmid=CreatShmid(4097);
if(shmid>0)
{
int i=0;
char *addr=shmat(shmid,NULL,0);
while(i<20)
{
addr[i ]='A';
addr[i]='