linux 共享内存 shmget

  74ac905cfa3740079f2f66a445a3d7c2.gif#pic_center


目录

前言

概述

原理机制

系统命令

接口说明

代码演示

结尾


前言

本专栏主要分享linux下并发编程相关知识,包括多进程,多线程,进程/线程间通信,并发同步控制,以及高并发下性能提升,请大家多多留言。


概述

共享内存是进程间通信的一种常用手段,相较于其它通信方法,它可以在进程间传递大量的不同格式的数据,同时这些数据不需要持久保存在磁盘上。

原理机制

共享内存相当于操作系统在进程的地址空间外,再开辟了一段物理内存,再把这段物理内存映射到进程的虚拟地址空间内,这样进程就可以访问了。

那么不同进程如何知道这段物理内存呢?

所以,第一步是确定一个唯一的key值,把这个key在不同进程间传递,不同进程拿到后就可以用这个key值向操作系统查到共享内存空间。

第二步,就是映射到进程的内存空间。我们都知道,进程的内存空间是一个虚拟地址空间,通过段页机制将物理内存地址转成虚拟内存地址,所以此处的共享内存,也需要把它挂到进程的虚拟地址空间中,进程才可以访问,不然还是找不到。

第三步,此时就可以直接读写了。

第四步,使用完成后,资源需要释放,否则会造成内存泄漏,这可是编程的大忌。因为涉及到多个进程共同使用,当然我们释放有两种形式,一是当前进程不再引用使用,此时共享内存还存在;一种是其它进程不再使用时,删除共享内存,此时共享内存就彻底不存在了。

系统命令

查询共享内存系统资源,使用系统命令

 ipcs -m

查询结果如下:

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status

0x0101de21 229412     test     600        8192       1

手动使用系统命令删除共享内存,使用共享内存的id

ipcrm -m shmid

接口说明

接口对应的头文件为

 #include <sys/types.h>

 #include <sys/ipc.h>

 #include <sys/shm.h>

(1)创建和获取已有的共享内存,每个共享内存都有唯一的key来标识,key值可以用IPC_PRIVATE,也可以用ftok函数生成。

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

size ,共享内存的大小,分配时会与PAGE_SIZE向上取整;

shmflg,可以取值

IPC_CREAT

创建共享内存,如果不带时,只是查找key值标识的共享内存

IPC_EXCL

与IPC_CREATE一起使用,如果已经有key标识的共享内存时,就会失败

SHM_HUGETLB

创建大页内存,一般页面大小为2KB/4KB,这里可以使更大的页面,在密集型读时可以得到性能提升;

SHM_HUGE_2MB

同上,创建2MB的大页内存

SHM_NORESERVE

不为此共享内存使用swap空间

(2)映射到进程私有虚拟地址空间

void * shmat(int shmid, char __user * shmaddr, int shmflg);

将shmid标识的共享内存,映射到shmaddr对应的进程内存地址上,映射后的地址是与SHMLBA向下对齐的地址。如果地址为空,则由系统选择一块进程空闲空间进行映射。

关于SHMLBA,这是关于CPU  cache调度相关,有些话长,在另外一篇博文中专门解释。

shmflg,标识共享内存的使用权限,可以取值

SHM_EXEC

共享内存可以有执行权限

SHM_RDONLY

以只读权限使用共享内存

SHM_REMAP

如果当前映射地址已经有映射有其它共享内存,可以进行替换

(3)解除与当前进程的映射

int shmdt(const void *shmaddr);

当然这里只是与当前进程解除了映射,内核资源也仅仅对引用计数减一,并没有删除;

(4)删除共享内存资源

int shmctl(int shmid, int cmd, struct shmid_ds * buf);

此系统函数,可以对共享内存进行一些控制操作,其中包括删除共享资源,由cmd来指定对应的操作;

cmd,可以取下面的值

IPC_STAT

调用者需要有读权限,会将kernal中共享内存信息拷到buf中返回

IPC_SET

可以设置shmid_ds结构成员的信息

IPC_RMID

销毁共享内存,当然必须是引用计数为0,调用者一定是创建者或最后一个使用进程

IPC_INFO

获取共享内存的系统限制相关参数值

SHM_INFO

获取共享内存资源使用情况

SHM_STAT

同IPC_STAT

SHM_LOCK

锁定共享内存,此时内存页面不会被替换

SHM_UNLOCK

解除锁定

(5)ftok系统函数对应的头文件与声明如下:

#include <sys/types.h>

#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);

代码演示

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define SHM_SIZE 8192
int main(int argc ,char *argv[])
{
        key_t   shm_key = ftok(".", 1);
        int shm_id = -1;
        char *pshm = NULL;
        char str[] = "Hello, World!";
        int pid = 0;
        int underSubprocess = 0;

        shm_id = shmget(shm_key, SHM_SIZE, 0600|IPC_CREAT);
        if(shm_id < 0)
        {
                printf("get shm error [%s]\n",strerror(errno));
                return -1;
        }

        pshm = (char *)shmat(shm_id, NULL, 0);
        if(pshm == (char *)-1)
        {
                printf("attach sharememory error [%s]\n", strerror(errno));
                return -1;
        }

        pid = fork();
        if(pid == 0)
        {
                // under subprocess
                printf("I'm in the subprocess\n");
                sleep(2);
                printf("recv: %s\n",pshm);
                underSubprocess = 1;
        }
        else if(pid > 0)
        {
                strncpy(pshm, str, sizeof(str));

                sleep(5);
                printf("I'm father ,will exit.\n");
        }
        else
        {
                printf("fork error\n");
        }

        if(-1 == shmdt(pshm))
        {
                printf("detach sharememory error [%s]\n",strerror(errno));
                return -1;
        }

        if(underSubprocess == 0)
                shmctl(shm_id, IPC_RMID, NULL);

        return 0;
}

在运行过程中查看系统共享内存

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status

0x0101de21 229412     test     600        8192       1

确实已经创建了。


结尾

作者邮箱:[email protected]
如有错误或者疏漏欢迎指出,互相学习。另外有什么想要了解的内容,也可以给我发邮件,互相谈讨,定知无不言。

注:未经同意,不得转载!

猜你喜欢

转载自blog.csdn.net/senllang/article/details/129943913