共享内存是最高效的IPC机制,因为它不涉及进程之间的任何数据传输 。这种高效率带来的问题是,我们必须用i其他辅助手段来同步进程对共享内存的访问,否则会产生竞态条件 。因此,共享内存通常和其他进程间通信方式一起使用 。
linux共享内存的API都定义在sys/shm.h头文件中,包括4个系统调用:shmget、shmat、shmdt和shmctl 。
shmget系统调用shmget系统调用创建一段新的共享内存,或者获取一段已经存在的共享内存 。定义如下:
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);和semget系统调用一样,key参数是一个键值,用来标识一段全局唯一的共享内存 。size参数指定共享内存的大小,单位是字节 。如果是创建新的共享内存,则size值必须指定 。如果是获取已经存在的共享内存,则可以把size设置为0 。
shmflg参数的使用和含义与semget系统调用的sem_flags参数相同 。不过shmget支持两个额外的标志:
- SHM_HUGETLB:类似于mmap的MAP_HUGETLB标志,系统将使用“大页面”来为共享内存分配空间
- SHM_NORESERVE:类似于mmap的MAP_NORESERVE,不为共享内存保留交换分区(swap空间) 。这样,当物理内存不足的时候,对该共享内存执行写操作将触发SIGSEGV信号 。
如果shmget用于创建共享内存,则这段共享内存的所有自己都被初始化为0,与之关联的内核数据结构shmid_ds将被创建并初始化 。shmid_ds结构体的定义如下:
struct shmid_ds{struct ipc_prem shm_prem;/*共享内存的操作权限*/size_t shm_segsz;/*共享内存大小,单位是字节*/__time_t shm_atime;/*对这段内存最后一次调用shmat的时间*/__time_t shm_dtime;/*对这段内存最后一次调用shmdt的时间*/__time_t shm_ctime;/*对这段内存最后一次调用shmctl的时间*/__pid_t shm_cpid;/*创建者PID*/__pid_t shm_lpid;/*最后一次执行shmat或shmdt操作的进程PID*/shmatt_t shm_nattach;/*目前关联到此共享内存的进程数量*//*省略一下填充字段*/}shmget对shmid_ds结构体的初始化包括:- 将shm_perm.cuid和shm_perm.uid设置为调用进程的有效用户ID
- 将shm_perm.cgid和shm_perm.gid设置为调用进程的有效组ID
- 将shm_perm.mode的最低9位设置为shmflg参数的最低9位
- 将shm_segsz设置为size
- 将shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0
- 将shm_ctime设置为当前的时间
#include <sys/shm.h>其中,shm_id参数是由shmget调用返回的共享内存标识符 。
void* shmat(int shm_id,const void *shm_addr, int shmflg);
int shmdt(const void* shm_addr);
shm_addr参数指定将共享内存关联到进程的哪块地址空间,最终的效果还受到shmflg参数的可选标志SHM_RND影响:
- 如果shm_addr为NULL,则被关联的地址由操作系统选择 。这是推荐的做法,以确保代码的可移植性 。
- 如果shm_addr非空,并且SHM_RND标志未被设置,则共享内存被关联到addr指定的地址处 。
- 如果shm_addr非空,并且设置了SHM_RND标志,则被关联的地址是[shm_addr - (shm_addr % SHMLBA)] 。SHMLBA的含义是“段低端边界地址倍数”(Segment Low Boundary Address Multiple),它必须是内存页面大小PAGE_SIZE的整数倍 。现在的Linux内核中,它等于一个内存页大小 。SHM_RND的含义是圆整(round),即将共享内存被关联的地址向下圆整到离shm_addr最近的SHMLBA的整数被地址处 。
- SHM_RDONLY:进程仅能读取共享内存中的内容 。若没有指定该标志,则进程可同时对共享内存进行读写操作(当然,这需要在创建共享内存的时候指定其读写权限)
- SHM_REMAP:如果地址shmaddr已经被关联到一段共享内存上,则重新关联
- SHM_EXEC:它指定对共享内存段的执行权限 。对共享内存而言,执行权限实际上和读权限是一样的 。
- 将shm_nattach加1
- 将shm_lpid设置为调用进程PID
- 将shm_atime设置为当前的时间
推荐阅读
- 德军骷髅师兵力是多少 德军骷髅师的战斗力
- 为什么法国的黑人那么多
- 金茯砖茶放多久,金花茯砖茶怎么喝
- 阴阳师提灯小僧哪里多简介
- 舒蕾洗发水价格是多少
- 碘甘油的用法方法
- 神经节甘脂是什么?
- 古代战场士兵死得有多惨
- 汉朝刘盈和刘恒的关系
- 集驗療癭酒方的功效与作用
