共享内存

  1. 前言

    • 主要是翻译链接地址.
    • 加上之前看的一些书籍的总结。
  2. 包含头文件

    • #include <sys/shm.h>
  3. int shmget(key_t key, size_t size, int shmflg);

    • 描述

      • 返回的是系统虚拟共享内存片段的shmid和传入key值存在映射。可以通过指令查看
        ipcs -m
        
      • 返回值还和一个数据结构存在映射关系,还和一篇共享内存存在映射关系。
      • 如果key值等于IPC_PRIVATE则会创建一个结构体,shmid,以及对应大小的内存。
      • 如果key不存在任何映射,但是声明了shmflag&IPC_CREAT,也会创建。
    • 创建的内容

      • 创建会创建一个结构体。
      • shm_perm.cuid,shm_perm.uid被设置为调用进程的用户ID.
      • shm_perm.cgid|shm_perm.gid被设置为调用进程的组ID.
      • shmflgshm_perm.mode保存,对低九位做与运算。
      • sizeshm_perm.segsz保存。
      • shm_lpid,shm_naatch,shm_atime,shm_dtime都被设为0.
      • shm_ctime被设置位当前时间。
      • 创建后可以通过函数int shmctl(int shmid, int cmd, struct shmid_ds *buf);获取对应的信息。

      • 共享内存创建之后被初始化为0.

    • key的值

      • key表示获取已经创建的,但是shmflg必须为0而且key & IPC_PRIVATE必须为0.或者就是创建新的。
      • IPC_PRIVATE只能是其子进程可以。通常和shmflg=0,key会创建一个私有的,但是不能已经存在。
    • shmflg的值

      • IPC_CREAT表示创建一个新的。如果没有则会找已经创建的与key相对应的内存,同时还会检查当前的调用者是否由权限使用这一块内存。
      • IPC_EXCLIPC_CREAT一起使用表示一定要新创建。如果已经存在则通过errnor返回错误。
      • SHM_HUGETLB使用大的页分区来分配共享内存。2.6以后。
      • SHM_HUGE_2MB|SHM_HUGE_1GB表示大表。自3.8以后。
      • SHM_NORESERVEmmap函数的MAP_NORESERVE同样的目的。表示这块不保留交互区。没有交换区就可能造成SIGSEGV的错误。
    • 错误码代表的含义,在errno.h中定义

      • EACCES没有权限。
      • EEXIST通过IPC_CREAT|IPC_EXECL的方式创建,同时声明了这两个flag,而且与key相关的共享内存已经存在。
      • EINVAL设置的size超过上限值SHMMAX|/proc/sys/kernel/shmmax,可以查看这两个值,修改这两个值。修改通过指令echo value > /proc/sys/kernel/shmmax的方式修改。也可能是小于最小值SHMMIN。或者是这个key对应的内存已经存在,但是size大于keysize.可以结合指令ipcs -m查看。
      • ENFILE系统设置的总的共享内存被用完。上面是单个的超过了限制,这个是总数上超过了限制。
      • ENOENT没有与key对应的内存存在。肯定没有传入IPC_CREAT
      • ENOMEM系统无法分配内存,这里是系统资源耗尽。
    • 资源限制

      • SHMALL限制了共享内存的总数,在/proc/sys/kernel/shmall由定义。

      • SHMMAX限制了共享内存的单次创建最大。在/proc/sys/kernel/shmmax

      • SHMMIN最小目前是1byte

      • SHMMNI共享内存可以有几个,在/proc/sys/kernle/shmmni中定义。

  4. void *shmat(int shmid, const void *shmaddr, int shmflg);

    • 功能

      • 将与shmid绑定的共享内存映射到调用者的shmaddr处。
    • shmaddr

      • 如果为NULL,系统自动选择一个合适的地方进行映射。
      • 如果不为空且shmflg&SHM_RND不为0.那么就按照页面对其的方式绑定到shmaddrsize=(size+SHMLBA-1)/SHMLBA*SHMLBA.
      • 其他的则是,shmaddr这个地址必须是按照页对齐的地方。
    • shmflg

    • SHM_EXEC表示这块内存可以用于执行,但是调用者需要由执行权限。
    • SHM_RDONLY绑定的这块内存只用于读取,否则就是读写。
    • SHM_REMAP占用进程一段地址。如果这段地址中有已经被占用的,则返回EINVAL,这种情况一般是使用shmaddr=NULL.
    • 返回值

      • 成功绑定后的地址起始位置。
      • 失败返回-1,同时哈辉设置errno为对应的错误代码。
  5. int shmdt(const void *shmaddr);

    • 功能

      • 解除调用者与shmaddr共享内存的映射关系。
    • shmaddr

      • 这个只应该是已经和调用者存在映射关系,而且这个值必须是由shmat调用的返回值。
    • 成功后

      • 修改对应的共享结构体的值,比如shm_dtime -> detach time,shm_lpid->last process id,shm_nattch->count of attach
    • 返回值

      • 成功返回0,失败返回-1,同时设置errno表示对应的错误。
  6. 错误值

    • shmat

      • EACCES表示没有权限。
      • EIDRM已经被删除,ID,REMOVED
      • EINVAL表示地址没对齐的方式映射,给的地址无效,不能绑定,或者是给了SHM_REMAP但是shmaddr为空。
      • ENOMEM系统没有内存为其分配描述符或者页表。
    • shmdt

      • EINVAL表示没有和shmaddr绑定的。或者地址不是起始地址,而是中间地址。
  7. 子进程

    • fork

      • 子进程会继承父进程的共享继承,都会绑定,任何权限的都会共享。
    • execve

      • 执行新的程序的时候就会取消绑定。
    • _exit

      • 退出的时候会取消绑定。
  8. 建议

    • shamt

      • 建议shmaddrNULL,因为不同的进程挂载的地方可能不同,而且有可能还不合法。随机的更加合理一些。
      • 甚至可以绑定一个被标记为即将删除的共享内存。
      • SHMLBA|segment low boundary address.这个表示调用者需要保证这个地址是这个的倍数。可以看成对齐。这个保证处理器缓存的执行其他的绑定。
  9. int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    • 功能

      • 完成cmd参数声明的指令。对应的虚拟内存由shmid表示。
      • buf则是一个结构体指针。这个结构体在sys/shm.h中定义。
    • shmid_ds成员

      • shm_perm:permission指向一个ipc_perm结构体,记录有共享内存的操作权限。
      • shm_segsz:segment size表示当前这个共享内存的大小。
      • shm_cpid:create process" id表示创建这个共享内存的进程号。
      • shm_lpid:last process id表示最后一个进程调用shmat,shmdt的进程。
      • shm_nattch:number of attch现在有多少的进程在使用这块内存。
      • shm_atime:attach time最后一个调用shmat函数的时间。
      • shm_dtime:detach time最后一个调用shmdt函数的时间。
      • shm_ctime:control time最后一个调用shmctl IPC_SET的时间。
    • cmd操作类型

      • IPC_STAT从内核中拷贝数据与shmid对应的共享内存的数据到buf中。但是调用者必须要有可读权限。
      • IPC_SETbuf的一些数据写入到内核的数据结构中。当然还有变量shm_ctime:control time.可以修改值shm_perm.uid,shm_perm,gid,shm_perm.mode等。
      • IPC_RMID标记删除,实际不会删除,会等待没有绑定为止,而且检查权限。
      • IPC_INFO返回共享内存的限制信息,通过buf返回,而且类型也会变成shminfo.所有解析的时候需要强转一下。如果值太大可能会不同,但是输出16进制可以查看。不同的Linux其中结构体shminfo也可能不同。
      • SHM_STAT,和IPC_STAT一样,返回结构体shmid_ds.然而shmid不再是一个绑定的key,而是内核中数组的的下标。
    • 返回值

      • IPC_INFO|SHM_INFO返回当前内核共享内存最大下标。这个参数可以用于SHM_STAT|SHM_STAT_ANY来获取共享内存的所有的信息,即shmid_ds
      • 如果SHM_STAT则成功返回对应的shmid。其他的成功返回0.失败则返回-1.并设置对应的errno.
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 共享内存