• linux 进程学习笔记-共享内存


    如果能划定一块物理内存,让多个进程都能将该内存映射到其自身虚拟内存空间的话,那么进程可以通过向这块内存空间读写数据而达到通信的目的。另外,和消息队列不同的是,共享的内存在用户空间而不是核空间,那么就不存在“用户空间和内核空间之间数据复制”的问题,这会减少不少开销。 
    
    由于不同进程都可能向同一个空间读写数据,所以其需要一些同步机制来防止混乱,可以使用的机制有“信号量”“文件锁”等。 
    
    共享内存有mmap和System V Shared Memory, 下面说的是后者。 
    
      
    
    创建或打开共享内存: 
    
    int shmget(key_t key, size_t size, int shmflg); 
    
    这与创建和打开消息队列的msgget非常类似,其同样用一个key_t类型的key来唯一标识被共享的内存。 size参数表示要创建的共享内存的大小,就像malloc函数一样。 shmflg参数和msgget函数的shmflg参数一样:其有两层含义,一是该参数可以取值IPC_CREATE,表示请求新建共享内存;也可以是 IPC_CREATE|IPC_EXCL的按位组合,表示请求新建共享内存但如果已经存在的话则报错。二是该参数表示权限控制,比如666表示全部可读写。那么如果该参数写成IPC_CREATE|IPC_EXCL|666则表示请求新建共享内存但如果已经存在的话则报错并且权限为666 
    
      
    
    将共享内存attach到进程自己的虚拟内存空间: 
    
    
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    
    shmid参数: 
    
    准备attach的共享内存id 
    
    shmaddr参数: 
    
    要将共享内存attach到的进程自己的虚拟空间地址,其需要和shmflg参数结合起来理解。 
    
    1)如果该参数传递一个空指针的话,则共享内存将被attach到由系统自动选择的第一块可能内存 
    
    2)如果该参数不为空: 
    
    2.1)如果 shmflg & SHM_RND 不为0,那么共享内存将被attach到这个地址: 
    
    (shmaddr -((uintptr_t)shmaddr %SHMLBA)).  
    
    其中,SHM_RND标识表示取整对齐(round), SHMLBA是共享内存低段地址,也就是附加共享内存的边界地址。那么上面的计算公式意思是说:将shmaddr指定的地址移动到第边界地址的整数倍上。相反的,如果shmflg & SHM_RND为0,则直接使用shmaddr指定的地址。 
    
    2.2)如果 (shmflg &SHM_RDONLY) 不为0,那么共享内存将变得只读(如果有读权限的话),相反的,(shmflg &SHM_RDONLY) 为0,则共享内存可读可写(如果有写权限的话) 
    
    当attach成功后,共享内存在进程虚拟空间中的首地址将被返回,这时你就可以像操作普通内存一样来使用它了。 
    
      
    
    attach的反向操作:将共享内存从进程的内存空间脱离 
    
    int shmdt(const void *shmaddr); 
    
    shmaddr参数就是原来attach上时的地址。 
    
      
    
    共享内存所对应的数据结构(shmid_ds)和消息队列的数据结构(msqid_ds)非常的类似,相关操作也雷同: 
    
    
    struct shmid_ds {
             struct ipc_perm         shm_perm;       /* operation perms */
             int                     shm_segsz;      /* size of segment (bytes) */
             __kernel_time_t         shm_atime;      /* last attach time */
             __kernel_time_t         shm_dtime;      /* last detach time */
             __kernel_time_t         shm_ctime;      /* last change time */
             __kernel_ipc_pid_t       shm_cpid;       /* pid of creator */
             __kernel_ipc_pid_t       shm_lpid;       /* pid of last operator */
             unsigned short          shm_nattch;     /* no. of current attaches */
             unsigned short          shm_unused;     /* compatibility */
             void                   *shm_unused2;   /* ditto - used by DIPC */
             void                   *shm_unused3;   /* unused */
     };
     
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    
    第一个参数表示要操作的共享内存的id 
    
    cmd参数表示要执行的操作,与msgctl函数类似: 
    
    1)IPC_STAT获取消息队列属性信息,并将这些信息放置到第3个参数所设置的buffer中 
    
    2)IPC_SET 根据buffer中的数据设置消息队列的一些属性,并非所有属性都可设置,其仅仅限于:ipc_perm.uid,ipc_perm.gid,ipc_perm.mode 这几种 
    
    3)IPC_RMID 删除消息队列。 
    
    注:IPC_SET和IPC_RMID都会进行相应的权限检查,只有具备权限的进程才能执行相关操作 
  • 相关阅读:
    11.26
    数组
    JavaScript
    2018.11.26
    input标签
    HPH 函数
    jQuery
    19/1/3数组
    2018/12/26//循环体
    12/25
  • 原文地址:https://www.cnblogs.com/zendu/p/4988360.html
Copyright © 2020-2023  润新知