嵌入式linux的学习笔记-共享内存(六)

时间:2022-12-26 22:34:13

共享内存
共享内存是可以被多个进程共享访问的一部分物理内存,如果多个进程都把一个内存区映射到自身的虚拟地址空间,则这些进程就可以直接访问该共享的内存区域,从而通过共享内存的方式实现多进程间的通讯,共享内存是进程间数据通讯的最快方法.
共享内存的实现分为两步:
1,创建共享内存,使用shmget函数
2,映射共享内存,将创建的共享内存映射到具体的进程空间中去,使用shmat函数

int shmget(key_t key,int size,int shmflg); //用于创建一个共享内存
共享内存对象的创建或获得。与其它IPC机制一样,进程在使用共享内存区域以前,必须通过系统调用sys_ipc (call值为SHMGET)创建一个键值为key的共享内存对象,或获得已经存在的键值为key的某共享内存对象的引用标识符。以后对共享内存对象的访 问都通过该引用标识符进行。对共享内存对象的创建或获得由函数sys_shmget完成.这里key是表示该共享内存对象的键值,size是该共享内存区 域的大小(以字节为单位),shmflg是标志(对该共享内存对象的特殊要求)。
这里key是表示该共享内存对象的键值,size是该共享内存区域的大小(以字节为单位),shmflg是标志(对该共享内存对象的特殊要求)。

它所做的工作如下:
1) 如果key == IPC_PRIVATE,则总是会创建一个新的共享内存对象。
但是 (The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more clearly show its function)
* 算出size要占用的页数,检查其合法性。
* 申请一块内存用于建立shmid_kernel数据结构,注意这里申请的内存区域大小不包括真正的共享内存区,实际上,要等到第一个进程试图访问它的时候才真正创建共享内存区。
* 根据该共享内存区所占用的页数,为其申请一块空间用于建立页表(每页4个字节),将页表清0。
* 搜索向量表shm_segs,为新创建的共享内存对象找一个空位置。
* 填写shmid_kernel数据结构,将其加入到向量表shm_segs中为其找到的空位置。
* 返回该共享内存对象的引用标识符。

2) 在向量表shm_segs中查找键值为key的共享内存对象,结果有三:
* 如果没有找到,而且在操作标志shmflg中没有指明要创建新共享内存,则错误返回,否则创建一个新的共享内存对象。
* 如果找到了,但该次操作要求必须创建一个键值为key的新对象,那么错误返回。
* 否则,合法性、认证检查,如有错,则错误返回;否则,返回该内存对象的引用标识符。

共享内存对象的创建者可以控制对于这块内存的访问权限和它的key是公开还是私有。如果有足够的权限,它也可以把共享内存锁定在物理内存中。

void *shmat(int shmid,char *shmaddr(NULL),int shmflg); //用于将共享内存区域映射到本进程空间
int shmid是那块共享内存的ID,也就是shmget的返回值
char *shmaddr是共享内存的起始地址
int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1


例子
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 2048

int main()
{
int shmid;      //共享内存id号
char *shmadd;   //创建本进程的共享内存映射空间
if((shmid=shmget(IPC_PRIVATE,BUFSIZE,0666))<0) //第一个参数固定,第二个参数是2k内存,第三个参数是可读可写
{
//创建共享内存失败,出错处理
}else
{
system("ipcs -m");      //执行系统命令, ipcs -m 进程间通讯状态 -m 活动的
printf("-----------------------------------\n");
}
shmaddr=shmat(shmid,NULL,0);        //将共享映射到本进程空间,并返回共享内存的地址
system("ipcs -m");      //执行系统命令, ipcs -m 进程间通讯状态 -m 活动的
printf("-----------------------------------\n");
shmadt(shmdt(shmaddr)); //断开映射
system("ipcs -m");      //执行系统命令, ipcs -m 进程间通讯状态 -m 活动的
printf("-----------------------------------\n");
}