科技报道|- 共享内存,多进程编程

共享内存是最高效的IPC机制 , 因为它不涉及进程之间的任何数据传输 。 这种高效率带来的问题是 , 我们必须用i其他辅助手段来同步进程对共享内存的访问 , 否则会产生竞态条件 。 因此 , 共享内存通常和其他进程间通信方式一起使用 。
Linux共享内存的API都定义在sys/shm.h头文件中 , 包括4个系统调用:shmget、shmat、shmdt和shmctl 。
shmget系统调用shmget系统调用创建一段新的共享内存 , 或者获取一段已经存在的共享内存 。 定义如下:
#includeintshmget(key_tkey,size_tsize,intshmflg);和semget系统调用一样 , key参数是一个键值 , 用来标识一段全局唯一的共享内存 。 size参数指定共享内存的大小 , 单位是字节 。 如果是创建新的共享内存 , 则size值必须指定 。 如果是获取已经存在的共享内存 , 则可以把size设置为0 。
shmflg参数的使用和含义与semget系统调用的sem_flags参数相同 。 不过shmget支持两个额外的标志:
SHM_HUGETLB:类似于mmap的MAP_HUGETLB标志 , 系统将使用“大页面”来为共享内存分配空间SHM_NORESERVE:类似于mmap的MAP_NORESERVE , 不为共享内存保留交换分区(swap空间) 。 这样 , 当物理内存不足的时候 , 对该共享内存执行写操作将触发SIGSEGV信号 。shmget成功时返回一个正整数值 , 它是共享内存的标识符 。 shmget失败时返回-1 , 并设置errno 。
如果shmget用于创建共享内存 , 则这段共享内存的所有自己都被初始化为0 , 与之关联的内核数据结构shmid_ds将被创建并初始化 。 shmid_ds结构体的定义如下:
structshmid_ds{structipc_premshm_prem;/*共享内存的操作权限*/size_tshm_segsz;/*共享内存大小 , 单位是字节*/__time_tshm_atime;/*对这段内存最后一次调用shmat的时间*/__time_tshm_dtime;/*对这段内存最后一次调用shmdt的时间*/__time_tshm_ctime;/*对这段内存最后一次调用shmctl的时间*/__pid_tshm_cpid;/*创建者PID*/__pid_tshm_lpid;/*最后一次执行shmat或shmdt操作的进程PID*/shmatt_tshm_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设置为当前的时间shmat和shmdt调用共享内存被创建/获取之后 , 我们不能立即访问它 , 而是需要先将它关联到进程的地址空间中 。 使用完共享内存之后 , 我们也需要将它从进程地址空间中分离 。 这两项任务分别由两个系统调用实现:
#include
void*shmat(intshm_id , constvoid*shm_addr,intshmflg);
intshmdt(constvoid*shm_addr);
其中 , shm_id参数是由shmget调用返回的共享内存标识符 。
shm_addr参数指定将共享内存关联到进程的哪块地址空间 , 最终的效果还受到shmflg参数的可选标志SHM_RND影响:
如果shm_addr为NULL , 则被关联的地址由操作系统选择 。 这是推荐的做法 , 以确保代码的可移植性 。 如果shm_addr非空 , 并且SHM_RND标志未被设置 , 则共享内存被关联到addr指定的地址处 。 如果shm_addr非空 , 并且设置了SHM_RND标志 , 则被关联的地址是[shm_addr-(shm_addr%SHMLBA)] 。 SHMLBA的含义是“段低端边界地址倍数”(SegmentLowBoundaryAddressMultiple) , 它必须是内存页面大小PAGE_SIZE的整数倍 。 现在的Linux内核中 , 它等于一个内存页大小 。 SHM_RND的含义是圆整(round) , 即将共享内存被关联的地址向下圆整到离shm_addr最近的SHMLBA的整数被地址处 。除了SHM_RND标志外 , shmflg参数还支持如下标志: