System V共享内存函数基础

System V共享内存函数基础_第1张图片

函数说明

shmget

int shmget(key_t key, size_t size, int shmflg);

通过参数key返回一个System V共享内存段关联标记。当key设置为IPC_PRIVATE或者不存在重复key shmflg 设置成IPC_CREATE的情况下,一个新的共享内存段被创建,分配的长度等于参数size并且和PAGE_SIZE对齐。
如果shmflg指定IPC_CREATE and IPC_EXCL而且一个共享内存段已经存在在key名下,函数将会调用失败,errno变量也会被设置成EEXIST错误。(这个效果类似open函数使用O_CREATE|O_EXCL)
shmflg有以下的组合方式

IPC_CREAT

去创建一个新段。如果这个flag没有用,shmget函数key名下将会找到段关联标记,并且检查调用函数的用户是否有权限去访问这个共享段。

IPC_EXCL

伴随着IPC_CREAT使用,用于确认失败情况下是否为段已经存在。

mode flags

指定权限授权给所有者、组和领域。这些bits和open函数参数中拥有相同的格式,相同的意义。目前,可执行权限没有在这系统中启用。

SHM_HUGETLB

(自从Linux 2.6)
允许段使用”巨型页”。阅读Linux内核文件HugeTLB获取更多信息。

SHM_NORESERVE

(自从Linux 2.6.15)
这个标记用于类似于mmap(2) MAP_NORESERVE 的意图。不要为这个段预存交换空间。当预存了交换空间,修改段将会获得一个保障。当没有预留交换空间,当没有足够的物理内存的时候去写的时候可能会出现SIGSEGV。

shmid_ds

当一个新的共享内存段被创建,它内存将会清理成0,而且他的关联数据结构 shmid_ds将会初始化成下面的样子:

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;  /* No. of current attaches */
               ...
           };
           struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };
变量 设置
shm_perm.cuid and shm_perm.uid 设置成调用者用户的ID
shm_perm.cgid and shm_perm.gid 设置成调用者的groupID
shm_perm.mode 低9位将会被设置成shmflg参数值
shm_segsz 设置成struct的size
shm_lpid, shm_nattch, shm_atime and shm_dtime 设置成0
shm_ctime 设置成时间戳

如果共享内存段已经存在,权限被验证,在删除的时候需要做检查。

返回值

如果成功将会返货共享内存的标示。发生错误的时候将会返回-1。

错误码

shmat

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

通过标记符挂载上一块共享内存到一块process的内存地址中。这个挂载地址是需要遵循下面的规则:
如果shmaddr为空,系统将会寻找一块合适的(没有使用)地址在被挂载段中。
如果shmaddr补位空而且SHM_RND被指定在shmfg,挂载发生的地址等于shmaddr地址按照SHMLBA对齐的位置。否则shmaddr必须是在一个页对齐的位置。
如果在shmfg中指定SHM_RDONLY,段在进程中只能读。否则这段是可以读写。没有只写不读的概念。
SHM_REMAP标记可能指定在shmflg中,去表示—映射的段可能替换任何存在的映射在shmaddr开始size大小的内存区域。在这个情况下shmaddr必须有值。
当挂载成功之后对于shmid_ds数据结构的修改如下:

变量 设置
shm_atime 设置成当前时间
shm_lpid 设置成本进程的编号
shm_nattch 将会+1

返回值

如果返回值为被释放掉的内存段地址;当错误发生的时候将会返回(void*)-1。

shmdt

int shmdt(const void *shmaddr);

释放掉一块共享内存的挂载;与shmat操作相反;
当调用成功之后将会触对shmid_ds的修改

变量 设置
shm_dtime 设置成当前时间
shm_lpid 设置成本进程的编号
shm_nattch 将会-1

返回值

如果返回值为0;当错误发生的时候将会返回(void*)-1。

shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
在shmid中执行一次cmd控制操作,返回值将会写入buf中,下面是命令描述:

变量 设置
IPC_STAT 复制当前共享内存的shmid_ds信息
IPC_RMID 标记共享内存需要被删除,当shm_nattch计数为0时将会回收,调用者必须是创建者,或者是privileged
IPC_INFO 返回系统级关于共享内存相关的参数配置,需要强转换类型为shminfo
SHM_INFO 返回shm_info信息
SHM_STAT 返回一个shmid_ds。shmid不是标识符,而是内核内部数组的下边
SHM_LOCK 防止共享内存段交换。锁定之后的共享内存块如果有调用者去操作页的时候将会触发失败
SHM_UNLOCK 解锁内存段,允许他被交换出去。
struct  shminfo {
    unsigned long shmmax; /* Maximum segment size */
    unsigned long shmmin; /* Minimum segment size; always 1 */
    unsigned long shmmni; /* Maximum number of segments */
    unsigned long shmseg; /* Maximum number of segments that a process can attach; unused within kernel */
    unsigned long shmall; /* Maximum number of pages of shared memory, system-wide */
};

IPC_INFO or SHM_INFO操作返回在内核记录全部共享内存队列记录信息中最高使用条目的下标(这个下标能用在SHM_STAT flag下获得系统中全部共享内存段);
SHM_STAT 将返回共享内存的标识符
其他操作将返回 0 作为成功;

你可能感兴趣的:(linux,共享内存)