一、共享内存的概念
内核中有一块公共的内存空间,两个不相关的进程都可以使用公共内存。独立于任何进程空间的一块共享空间,我们普通的内存操作来操作共享内存。它们都存在于<sys/ipc.h>、<sys/shm.h>两个头文件中。
二、相关的API介绍
1. int shmget (key_t key,size_t size,int shmflg)
创建/获取一个共享内存。
参数说明:
1. key和昨天的消息队列中的key 是一样的,这里它是内存的索引,同样可以用ftok来转换键值;
2. size 为共享内存的空间,以Mb 为单位来申请。在创建一段共享内存时,必须指定size 的大小,若共享内存的已存在,size应该为0;
3. flag 可以赋值 IPC_CREAT 来实现创建共享内存,若为0,即会以默认的方式来获取共享内存。
返回值: 成功返回共享内存的ID(shmid),失败返回 -1 ;
用法:
key_t key;
shmget(key,1024*2,IPC_CREAT|0600);//创建一个 2M 的可读可写的共享内存
2. void *shmat (int shm_id,cont void *addr,int shmflg)
把共享内存连接到当前进程。
参数说明:
1. shm_id 是共享内存的ID,可以通过它找到想要的共享内存;
2. *addr 指定共享内存连接到当前进程中的地址,通常为0,标识由系统来选择共享内存的地址。
3. shmflg 标志位,通常为0,表示可读可写;
这个函数就是把共享内存的某个地址连接到当前进程的空间,所以需要一个指针来表示这个内存地址。
用法:
char *shmaddr;
shmaddr=shmat(shmid,0,0);//使用默认方式来连接
3. int shmdt ( void *addr)
断开共享内存的连接。
参数说明: *addr 需要断开的地址;
用法:
char *shmaddr;
shmaddr=shmat(shmid,0,0);//使用默认方式来连接
shmdt(shmaddr);
4. int shmctl ( int shm_id,int cmd,struct shmid_ds *buf)
控制内存函数。
参数说明:
1. shm_id 共享内存的ID号;
2. cmd 控制命令,赋值IPC_RMID 表示移除共享内存;
3. *buf 为指令执时的信息结构体,比如执行的时间就存放在这个结构体当中,通常为0或 NULL;
返回值: 成功返回0,失败返回 -1。
用法: 以移除命令为例
shmctl(shmid,IPC_RMID,NULL);
熟悉了这些API之后,我们可以做个实验来深入学习一下编程时的具体用法。
三、小实验
编写两个程序,一个负责往共享内存写入数据,暂且命名为:SHM_demo1.c,另一负责读取共享内容,命名为:SHM_semo2.c
编程思路
SHM_demo1.c 代码
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
char *shmaddr;
key_t key;
key=ftok(".",12);
shmid=shmget(key,1024*2,IPC_CREAT|0600);//创建共享内存
if(shmid==-1){
printf("Shm creat failuer!\n");
exit(-1);
}
shmaddr=shmat(shmid,0,0);//连接到进空间
printf("shmat OK!\n");
strcpy(shmaddr,"This Send!\n");//直接往共享内存的地址写入数据
sleep(10);
shmdt(shmaddr);//断开连接,
shmctl(shmid,IPC_RMID,NULL);//移除共享内存
printf("shm over!\n");
return 0;
}
开始写入后,等待10秒钟,给足够的时间让另一个进程读取数据,然后断开连接后移除共享内存。
SHM_demo2.c 代码
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
char *shmaddr;
key_t key;
key=ftok(".",12);
shmid=shmget(key,1024*2,0);//获取共享ID,不用创建了,因为上面那个程序已经创建
if(shmid==-1){
printf("Shm creat failuer!\n");
exit(-1);
}
shmaddr=shmat(shmid,0,0); //连接到当前进程空间
printf("shmat OK!\n");
printf("shm data:%s\n",shmaddr);//直接读取显示
return 0;
}
两个程序配合的运行结果
SHM_demo1.c 编译为 write;SHM_demo2.c编译为read
如果读取第二次会怎么样呢?
可以看到,读取第二次,就显示共享内存创建错误了,因为我们在SHM_demo1.c 中移除了共享内存,SHM_demo2.c 必须在10秒以内读取,不然就会出现错误。