tlpi: System V共享内存

本文详细介绍了Linux系统V共享内存的概念、创建与使用,包括shmget、shmat、shmdt等系统调用的参数及作用。共享内存允许进程间高效通信,通过共享内存段实现数据的快速交换,其地址在不同进程中的相对位置和指针使用也有所阐述。此外,还提到了shmctl系统调用用于进行共享内存的控制操作,如权限设置、段的删除等。
摘要由CSDN通过智能技术生成

System V共享内存

1.概念
  • 共享内存允许多个进程之间共享物理内存的同一块区域,这块区域通常被称为共享内存段

  • 使用该共享内存段需要将该共享内存段附加到进程的虚拟地址空间中,该共享内存段会成为进程用户空间内存段的一部分,内核并不参与,与管道和消息队列需要将数据送入内核内存相比,共享内存的速度是所有IPC对象中最快的

2.创建或打开一个共享内存段

shmget()创建一个共享内存段或获取一个已有段的标识符,新创建的段中的内容会被置为0

#include<sys/types.h>
#include<sys/shm.h>
int shmget(key_t key, size_t size, int shmglg);
							//成功:返回共享内存段标识符  失败:返回-1

参数解释

  • key

    用于生成共享内存段的键

  • size

    如果是获取一个已有共享内存段,那么该参数不会对已有段产生任何效果,不过该参数仍然要求小于或等于段的大小

    如果是创建一个新的段,那么size表示需要分配的字节数,该参数实际上会被提升至系统分页大小的整数倍

  • shmflg

    用于指定新创建的内存段的权限,或者用来检查已有内存段的权限,还可以OR上下面的掩码

    IPC_CREATE如果没有已有段,创建一个新段
    IPC_EXCL与IPC_CREATE搭配使用,只用于创建新段,不会打开已有段
    SHM_HUGETLB创建一个使用hugepage的共享内存段,可以用来减少TLB表的条目数目
    SHM_NORESERVE待续
3.使用共享内存

shmat()系统调用将shmid标识的共享内存段附加到调用进程的虚拟地址空间

#include<sys/types.h>
#include<sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
						//成功:返回共享内存段的地址  失败:返回 (void *) -1

参数解释

  • shmid

    共享内存段标识符

  • shmaddr

    用于指定附加的位置,与shmflg的SHM_RND选项有关

    • 如果shamddr为NULL, 那么段会被附加到一个由内核选择的合适的地址(推荐使用)

    • 如果shamaddr不为NULL并且没有设置SHM_RND标志,那么shamaddr会被附加到指定的地址

      如果该地址不是系统分页大小的整数倍,那么会发生EINVAL错误

    • 如果shmaddr不为空并且设置了SHM_RND标志,那么段地址会被映射到SHMLBA(shared memory low boundary address指定

      的地址),该常量为系统分页大小的某个倍数,有助于提高系统性能

  • shmflg

    描述
    SHM_RDONLY附加只读段
    SHM_REMAP替换shmddr所在的当前共享内存段,此时shmaddr不能为NULL
    SHM_RND将shmaddr四舍五入为SHMLBA字节的倍数

    shmdt()系统调用将共享内存段分离出其虚拟地址空间

    #include<sys/type.h>
    #include<sys/shm.h>
    int shmdt(const void *shmaddr);
    				//成功:返回0 失败:返回-1
    
  • 通过fork()创建的子进程会继承其父进程附加的共享内存段

  • 在进程使用exec()后,所有附加的共享内存段都会被分离,在进程终止之后共享内存段也会自动被分离

5.共享内存在虚拟内存中的位置

如果采用内核推荐的方式,那么一个典型的进程地址空间布局就会如图所示

在这里插入图片描述

附加共享内存段的虚拟地址从0x40000000开始,位于堆和栈之间未使用的区域,内存映射和共享库也被放置在这个区域

通过修改内核常量TASK_UNMAPPED_BASE就可以修改这个起始地址

如果采用了非内核推荐的方法附加内存段,那么该起始地址可以被放在小于TASK_UNMAPPED_BASE所在的地方

6.在共享内存中使用指针

由于共享内存很有可能被附加到多个进程的虚拟地址空间,所以其地址在不同虚拟地址中可能是不同的,所以不能够在共享内存中使用指向绝对地址的指针,应该使用相对偏移量

在这里插入图片描述

*p = target;       //!wrong
*p = (target - baseaddr); target = baseaddr + *p; //right 
7.共享内存控制操作

shmctl()系统调用在shmid标识的共享内存段上执行一组控制操作

#include<sys/types.h>
#include<sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
								//成功:返回 0 失败: 返回-1

参数解释

  • shmid

    共享内存标识符

  • cmd

    cmd可以取如下值

    • IPC_RMID

      标识这个共享内存段以便删除,如果当前没有进程附加该段,那么就会立即执行删除操作,否则在所有进程都与该段进行分离后删除

    • IPC_STAT

      将与这个共享内存段关联的shmid_ds数据结构的一个副本复制到buf指向的缓冲区

      shmid_ds结构如下

      struct shmid_ds {
          struct ipc_perm shm_perm;    /* Ownership and permissions */
          size_t          shm_segsz;   /* Size of segment (bytes) */
          time_t          shm_atime;   /* Last attach time */
          time_t          shm_dtime;   /* Last detach time */
          time_t          shm_ctime;   /* Last change time */
          pid_t           shm_cpid;    /* PID of creator */
          pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
          shmatt_t        shm_nattch;  /* number of current attaches */
          ...
      };
      

      ipc_perm结构如下

      struct ipc_perm{
      	key_t 		__key;			//get()调用提供
      	uid_t 		uid;
      	gid_t 		gid;			//IPC对象的拥有者的uid和gid,这两个字段可以使用ctl()调用进行更改
      	uid_t		cuid;
      	gid_t 		cgid;			//IPC对象创建者的uid和gid,这两个字段不会改变
      	unsigned  short mode;		//IPC对象权限掩码
      	unsigned  short __seq;		//序列号
      }
      
    • IPC_SET

      使用buf指向的缓冲区来更新这个域共享内存相关的shmid_ds数据结构

    加锁和解锁

    • SHM_LOCK

      该标志可以将一个共享内存锁进RAM(内存

    • SHM_UNLCOK

      该标志可以将一个共享内存解锁以允许共享内存分页被交换出内存

    将共享内存锁进内存提高速度,避免因为页错误而延迟,当指定SHM_LOCK标志时不会立即将所有的分页锁进内存中,当共享内存分页第一次被进程附加到进程虚拟地址中(此时进入内存),他就会被所在内存中

    • SHM_LOCK

      该标志可以将一个共享内存锁进RAM(内存

    • SHM_UNLCOK

      该标志可以将一个共享内存解锁以允许共享内存分页被交换出内存

    将共享内存锁进内存提高速度,避免因为页错误而延迟,当指定SHM_LOCK标志时不会立即将所有的分页锁进内存中,当共享内存分页第一次被进程附加到进程虚拟地址中(此时进入内存),他就会被所在内存中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值