共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
1.特点
1.共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
2.因为多个进程可以同时操作,所以需要进行同步。
3.信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
2.原型
#include <sys/ipc.h>
#include <sys/shm.h>
/* 创建或获取一个共享内存:成功返回ID,失败-1*/
int shmget(key_t key, size_t size, int shmflg);
参数1:大多用ftok获取key值
参数2:共享内存的长度,以字节为单位
参数3:为所需要的操作和权限,可以用来创建一个共享存储空间并返回一个标识符或者获得一个共享标识符
flag的值为IPC_CREAT:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则直接返回共享存储标识符。
flag的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则产生错误。
/* 连接共享内存到当前进程的地址空间:成功返回只想共享内存的指针,失败-1*/
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数1:为shmget生成的共享存储标识符
参数2:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
参数3:为对数据的操作,如果指定为SHM_RDONLY则以只读方式连接此段,其他值为读写方式连接此段。
/* 断开与共享内存的连接:成功返回0,失败-1*/
int shmdt(const void *shmaddr);
参数1:addr为shmat函数返回的地址指针
/* 控制共享内存的相关信息:成功0,失败-1*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数1:shmget函数返回的共享存储标识符
参数2:cmd有三个,常用删除共享内存的为IPC_RMID;
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中;
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内。
简单的demo:创建一个共享内存,让服务端和客户端同时读取共享内存上的数据
shw_write.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MSG_FILE "/etc/passwd"
int main()
{
key_t key;
key = ftok(MSG_FILE,'z');
if(key < 0){
printf("ftok error!!\n");
exit(-1);
}
int shm_ID;
char *shmaddr;
shm_ID = shmget(key,4096,IPC_CREAT|0666);
if(shm_ID == -1){
printf("shmget error!\n");
perror("why");
exit(-1);
}
shmaddr = shmat(shm_ID,0,0);
printf("shmat OK\n");
strcpy(shmaddr,"hello world");
sleep(10);
shmdt(shmaddr);
shmctl(shm_ID,IPC_RMID,0);
printf("quit\n");
return 0;
}
shw_read.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MSG_FILE "/etc/passwd"
int main()
{
key_t key;
key = ftok(MSG_FILE,'z');
if(key < 0){
printf("ftok error!!\n");
exit(-1);
}
int shm_ID;
char *shmaddr;
shm_ID = shmget(key,4096,0);
if(shm_ID == -1){
printf("shmget error!\n");
perror("why");
exit(-1);
}
shmaddr = shmat(shm_ID,0,0);
printf("shmat OK\n");
printf("read this :%s\n",shmaddr);
sleep(2);
shmdt(shmaddr);
shmctl(shm_ID,IPC_RMID,0);
printf("quit\n");
return 0;
}