共享内存区的使用

共享内存区:

共享内存区时IPC形式中最快的。因为当共享内存区映射到共享它的进程的地址空间,这些进程间
数据的传递就不在涉及内核(进程不在通过执行任何进入内核的系统调用来传递数据)。

与其他IPC形式相比,进程通过共享内存区传递数据的步骤:

 

注意:默认情况下,通过fork()派生的子进程并不与其父进程共享内存区

使用共享内存区时所需的函数:

mmap()函数:

为何使用mmap()函数:
1.使用普通文件以提供内存映射I/O
2.使用特殊文件以提供匿名内存映射
3.使用shm_open以提供无亲缘关系进程间的Posix共享内存区
#include <sys/mman.h>

// 将一个文件或一个Posix共享内存区对象映射到调用进程的地址空间
// 成功返回被映射区的起始地址,出错返回MAP_FAILED
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
// addr:可以指定描述符fd应被映射到的进程内空间的起始地址(通常addr被指定为NULL,让内核自己选择起始地址)
// len: 映射到调用进程地址空间的字节数,它从被映射文件开头其第offset个字节出开始算
// prot:指定内存映射区保护(PROT_READ可读、PROT_WRITE可写、PROT_EXEC可执行、PROT_NONE不可访问)
// flags:指定进程对被映射数据所做的修改是否对共享该对象的其他进程共享,其值如下:
//     必须为MAP_SHARED(共享)或MAP_PRIVATE(私有)之一,可以或上(|)MAP_FIXED(准确的解释addr值)
//     共享即意味着该修改改变该共享对象的底层支撑对象(如某个文件,该文件被映射,此文件为底层支撑对象)
// fd: 被映射的文件的描述符
// offset: 偏移量(一般该值为0)
// 为了可移植考虑,一般将addr指定为空指针,并且不指定MAP_FIXED

munmap()函数:

#include <sys/mman.h>

// 删除一个映射关系、
// 成功返回0,出错返回-1
int munmap(void *addr, size_t len);
// addr:是由mmap()返回的地址
// len:映射区大小

msync()函数:

官方说明

#include <sys/mman.h>

// 使得硬盘中的文件与内存映射区内容一致,使用msync()执行同步
// 成功返回0,出错返回-1
int msync(void *addr, size_t len, int flags);
/*
关于addr和len参数的说明
The addr argument is the address of the first page of mapped memory to be synchronized.
The address must be on a page boundary, but need not be the first byte of the entire 
area mapped to a file. 
The len argument specifies the number of bytes of memory to be synchronized. If the length
does not specify an integral number of pages, it is rounded up to do so. The length need
not specify the entire area of mapped memory. 
*/
// flags: 取值为MS_ASYNC(异步写)或MS_SYNC(同步写)之一,还可以或上MS_INVALIDATE()

Posix共享内存区:

Posix提供的两种在无亲缘关系的进程间共享内存区的方法:
1.内存映射文件:由open()打开某个文件,再由mmap()将得到的描述符映射到当前进程地址空间中
的一个文件。
2.共享内存区对象:有shm_open()打开一个Posix IPC名字(可能是文件系统中的一个路径名),所返
回的描述符有mmap()映射到当前进程的地址空间。

shm_open()函数:

#include <sys/mman.h>

// 创建一个新的共享内存区对象,或打开一个已存在的共享内存区对象
// 成功返回非负描述符,出错返回-1
int shm_open(const char *name, int oflag, mode_t mode);
// name: Posix IPC名字,name参数随后也作为希望共享该内存区的任何其他进程使用
// oflag: 该参数必须含有O_RDONLY(只读)或O_RDWR(读写),可以或上O_CREAT,O_EXCL,O_TRUNC
// 若 oflag = O_RDWD | O_TRUNC,且所需共享内存区对象已存在,那么它的长度被截短成0
// mode:权限位,在没有指定O_CREAT时mode可以为0,当指定了O_CREAT后,mode参数必须指定

创建新的IPC对象所用的mode常值:
S_IRUSR    用户(属主)读
S_IWUSR    用户(属主)写
S_IRGRP    属组读
S_IWGRP    属组写
S_IROTH    其他用户读
S_IWOTH    其他用户写

shm_unlink()函数:

#include <sys/mman.h>

// 删除一个共享内存区对象名字,防止后续的open调用成功(与unlink、ma_unlink、sem_unlink类似)
// 成功返回0,出错返回-1
int shm_unlink(const char *name);

System V共享内存区:

与Posix共享内存区类似,只不过将shm_open()、mmap()调用换成了shmget()、shmat()调用sem_post

shmid_ds结构:

#include <sys/shm.h>

// 内核为每个共享内存区维护的信息结构
struct shmid_ds{
    struct ipc_perm shm_perm;
    size_t          shm_segsz;
    pid_t           shm_lpid;
    pid_t           shm_cpid;
    shmatt_t        shm_nattch;
    shmat_t         shm_cnattch;
    time_t          shm_atime;
    time_t          shm_dtime;
    time_t          shm_ctime;
};

shmget()函数:

#include <sys/shm.h>

// 创建一个新的共享内存区,或访问一个已存在的共享内存区
// 成功返回共享内存区标识符,出错返回-1
int shmget(key_t key, size_t size, int oflag);
// key:System V IPC名字,可以是ftok()返回值,也可以是IPC_PRIVATE
// size:指定内存区大小,单位为字节
//    当创建一个新的共享内存区时,该内存区被初始化为size字节的0
//    当访问一个已存在的共享内存区时,size应为0
// oflag:同shm_open()的oflag参数

shmat()函数:

#include <sys/shm.h>

// 在shmget()打开一个共享内存区后,shmat()将其附接到调用进程的地址空间
// 成功返回映射区起始地址,出错返回-1
void *shmat(int shmid, const void *shmaddr, int flag);
// shmid: 有shmget()返回的标识符
// shmaddr: 为空时,系统替调用者选择指定共享内存区在调用进程内的起始地址
//          非空时,返回地址取决于flag参数
// flag: 指定了SHM_RND时,相应共享内存区附接到由shmaddr参数指定的地址
//       没有指定SHM_RND,相应共享内存区附接到由shmaddr参数指定的地址向下舍入一个SHMLBA常值
// 默认情况下,只要调用进程具有某个共享内存区的读写权限,它附接到该内存区后就能读写该内存区
// flag指定为SHM_RDONLY时,限定只读访问共享内存区

shmdt()函数:

#include <sys/shm.h>

// 断接某个已附接的共享内存区
// 成功返回0,出错返回-1
int shmdt(const void *shmaddr);
// shmaddr: 某个已附接的共享内存区的起始地址

shmctl()函数:

#include <sys/shm.h>

// 对共享内存区的各种操作
// 成功返回0,出错返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buff);
// shmid: 共享内存区标识符
// cmd:操作命令
// buff:共享内存区信息结构的一个指针

cmd命令:
IPC_RMID:将由shmid指定的共享内存区从系统删除,并释放或回收期对应的数据结构
IPC_SET:通过buff指向的结构,设置指定共享内存区的shmid_ds结构的shm_perm.uid shm_perm.gid shm_perm.mode
IPC_STAT: 通过buff返回指定共享内存区当前的shmid_ds结构

原文地址:https://www.cnblogs.com/lnlin/p/9783394.html