Linux 共享内存----进程间通信
共享内存:
1.共享内存是最为高效的进程间通信方式
2.共享内存往往需要同步与互斥的机制(信号灯集)
3.ipc 对象不会随进程的结束而销毁,可以多次利用。必须手动注销或者系统重新启动才会销毁。
/usr/include/linux 中shm.h里对共享内存的大小,数量进行了规定,以及属性信息。
ipcs -m 查看共享内存
ipcs -q 查看消息队列
ipcs -s 查看信号量集
ipcrm -m id 删除一个ipc对象
-s
-q
key_t ftok(const char *pathname, int proj_id);
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
功能:获取一个key值
参数:pathname 文件
proj_id 大于0 整数
返回值:key -1
int shmget(key_t key, size_t size, int shmflg);
头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
功能:创建或者打开一个共享内存
参数:key:用来唯一识别一个ipc对象
size:要申请的共享内存的大小,以字节为单位
shmflg:打开一个共享内存的权限
IPC_CREAT:创建一个ipc对象
IPC_EXCL:如果这个对象已经存在则返回errno=EEXIST
mode:创建权限(0666/0766)
返回值:共享内存表示符 -1
void *shmat(int shmid, const void *shmaddr, int shmflg);
头文件:
#include <sys/types.h>
#include <sys/shm.h>
功能 : 映射一个共享内存
参数 :shmid : 共享内存标识符
shmaddr : 指定映射共享内存的首地址 (可以用malloc 申请空间)
NULL表示系统自动分配地址
shmflg : 共享内存的使用权限 SHM_RDONLY 表示只读
0 表示可读可写
返回值 : 返回映射共享内存首地址
返回错误码
int shmdt(const void *shmaddr);
头文件:
#include <sys/types.h>
#include <sys/shm.h>
功能: 消除一个映射
(进程结束或者共享内存被销毁后,映射关系会自动断开。但是我们通常习惯在用完后用手动方式消除映射)
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
功能 : 共享内存控制
参数 : shmid
cmd 操作命令
IPC_STAT (获取对象属性)
IPC_SET (设置对象属性)
IPC_RMID (删除对象)
buf :共享内存属性
struct shmid_ds buf;
shmctl(shmid,IPC_STAT,&buf); ------> 获取共享内存属性放到buf中
shmctl(shmid,IPC_SET,&buf); ------> 将共享内存属性设置为buf内容
shmctl(shmid,IPC_RMID,NULL);------》删除共享内存
返回值 0 -1
共享内存创建和使用顺序:
设置key值 ------》创建或者打开共享内存-----》映射共享内存 -----》使用共享内存 -----》解除映射 -----》删除共享内存
下面来看看两个demon程序,read和write:
//sharewrite.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#define ERROR -1 //在开发中,可以考虑定义成宏的形式来表示某些返回状态,或者是使用枚举的形式
#define success 0
int main(void){
key_t keyVal;
int shmid;
char *shm=NULL;
keyVal=ftok(".",'a'); //创建一个key值
if(ERROR==keyVal){
printf("ftok key create fail\n");
return ERROR;
}else{
printf("key:%d\n",keyVal);
}
shmid=shmget(keyVal,128, IPC_CREAT|0666); //获取共享内存的表示ID
if(ERROR==shmid){
printf("shmget fail\n");
return ERROR;
}else{
printf("shmget success\n");
}
shm=(char *)shmat(shmid,0,0); //映射并获得共享内存的首地址
if(NULL==shm){
printf("shmat fail\n");
return ERROR;
}else{
printf("shmat success\n");
}
char buf[256] = {0};
while(1){
fgets(buf,256,stdin); //从终端获取内容
strncpy(shm,buf,256); //写入到共享内存中
if(strncmp(buf,"quit",4)==0){
break;
}
sleep(1);
}
int id=shmdt((void *)shm); //解决共享内存的映射
if(id==ERROR){
printf("shmdt fail\n");
return ERROR;
}
struct shmid_ds sbuf;
int ret=shmctl(shmid, IPC_RMID, &sbuf); //IPC_RMID:删除共享内存
if(ERROR==ret){
printf("shmctl fail\n");
return ERROR;
}
return 0;
}
//shareread.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#define ERROR -1
#define success 0
int main(void){
key_t keyVal;
int shmid;
char *shm=NULL;
keyVal=ftok(".",'a'); //创建一个key值
if(ERROR==keyVal){
printf("ftok key create fail\n");
return ERROR;
}else{
printf("key:%d\n",keyVal);
}
shmid=shmget(keyVal,128, IPC_CREAT|0666); //获取共享内存的表示ID
if(ERROR==shmid){
printf("shmget fail\n");
return ERROR;
}else{
printf("shmget success\n");
}
shm=(char *)shmat(shmid,0,0); //映射并获得共享内存的首地址
if(NULL==shm){
printf("shmat fail\n");
return ERROR;
}else{
printf("shmat success\n");
}
char buf[256] = {0};
while(1){
if(shm[0]!='\0'){ //如果共享内存的第一个位置不是‘\0’,表示有内容写入了
printf("%s\n",shm);
}
if(strncmp(shm,"quit",4)==0){
break;
}
memset(shm,0,128); //每次需要清空一下内存中的内容
sleep(1);
}
int id=shmdt((void *)shm); //解决共享内存的映射
if(id==ERROR){
printf("shmdt fail\n");
return ERROR;
}
struct shmid_ds sbuf;
int ret=shmctl(shmid, IPC_RMID, &sbuf); //IPC_RMID:删除共享内存
if(ERROR==ret){
printf("shmctl fail\n");
return ERROR;
}
return 0;
}
在开始运行之前,先看一是否有已经创建好的共享内存
通过图片中看到,目前没有刚刚创建好的共享内存,那就先运行shareread,看看结果
发现已经创建好一个属于aaron的共享内存区域,大小为128 bytes,nattch的数值为1,那接下来运行sharewrite,看看结果如何:
发现nattch的数值已经变为了2,说明已经运行和创建成功现在就可以进行通信了,来看看效果吧
接下来输入quit看看是什么样的结果:
创建的共享内存已经消失了。