Linux—进程间通信—共享内存详解

本章目录

  • 1. 共享内存原理
  • 2. 创建共享内存
  • 3. 查看共享内存
  • 4. 附加共享内存到进程
  • 5. 代码验证接口
  • 6. 共享内存特性

1. 共享内存原理

  1. 首先在物理内存当中创建一块物理内存
  2. 不同的进程通过页表映射,将同一块物理内存映射到自己的虚拟地址空间
  3. 不同的进程,操作进程虚拟地址,通过页表的映射,就相当于操作同一块内存,从而完成数据的交换
  4. 具体图示:
    Linux—进程间通信—共享内存详解_第1张图片

2. 创建共享内存

  • 创建共享内存函数
    int shmget(key_t key, size_t size, int shmflg ) ;

    key:共享内存的标识符,用来标识一块共享内存,在操作系统当中,共享内存的标识符是不能重复的, 可以直接给32位的16进制数字。
    size:共享内存的大小
    shmflg

          IPC_CREAT:如果key标识的共享内存不存在,则创建
          IPC_EXCL | IPC_CREAT:如果key标识共享内存存在,则报错
          权限:按位或8进制数字 0664 (这是共享内存的读写属性)
    

    返回值:-1:失败了
    小于0:则成功,返回的是,共享内存的操作句柄,后续是通过操作句柄来进行操作共享内存的

3. 查看共享内存

  • 命令:ipca -m
  • 查看介绍
    Linux—进程间通信—共享内存详解_第2张图片
  • 共享内存的生命周期跟随操作系统的内核

4. 附加共享内存到进程

  • 附加共享内存到进程相关函数
    void *shmat ( int shmid, const void * shmaddr,int shmflg);

    shmid:共享内存操作句柄,shmget的返回值
    shmaddr:将共享内存附加到shmaddr,一般情况下,都不会自己去指定映射到共享区当中的那一段虚拟地址,而是传递NULL值,让操作系统去选择。
    shmflg

          标志将共享内存附加到进程以后,进程对共享内存的读写属性 
          0:读写         
          SHM_RDONLY :只读
    

    返回值:[附加成功]:返回值为附加到虚拟进程中的虚拟地址。 [附加失败]:NULL

  • 分离共享内存
    int shmdt(const void *shmaddr);
    shmaddr: 刚附加的时候,返回共享区的地址

  • 共享内存操作函数
    int fcntl(int fd,int cmd,…)
    int shmctl (int shmid,int cmd,struct shmid_ds *buf );
    shmid:共享内存操作句柄
    cmd:

         IPC_STAT :获取共享内存参数
         IPC_SET :设置共享内存属性
         IPC_RMID :删除共享内存
    

    struct shmid_ds :共享内存属性对应的结构体 ,删除时可以用NULL代替
    Linux—进程间通信—共享内存详解_第3张图片

5. 代码验证接口

  1. 首先是常见一个写进程,往共享内存当中写入内容
#include 
#include 
#include 
#include 

#define KEY 0x77777777

int main()
{
     
    int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);//创建共享内存
    if(shmid < 0)
    {
     
        perror("shmget");
        return 0;
    }

    //附加到当前的进程
    void* addr = shmat(shmid, NULL, 0);
    if(addr == NULL)
    {
     
        perror("shmat");
        return 0; 
    }

    //往共享内存写当中写
    sprintf((char*)addr, "%s", "i am process");
    shmdt(addr);
    return 0;
}
  1. 之后再创建一个读进程,从共享内存当中读
#include 
#include 
#include 

#define KEY 0x77777777

int main()
{
     
    int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);
    if(shmid < 0)
    {
     
        perror("shmget");
        return 0;
    }

    //附加到当前的进程
    
    void* addr = shmat(shmid, NULL, 0);
    if(addr == NULL)
    {
     
        perror("shmat");
        return 0; 
    }
    printf("addr : %s\n", (char*)addr);
    shmdt(addr);
    return 0;
}

运行结果:
Linux—进程间通信—共享内存详解_第4张图片

6. 共享内存特性

  1. 共享内存读取数据的时候,是采用拷贝的方式,而不是类似于管道的方式,将数据读走,也就是数据读过之后,数据还存在。
  2. 共享内存写的时候,采用覆盖写的方式。
  3. 如果删除了一个被进程附加的共享内存:
  • 当前共享内存的标识符会被改变成0x00000000 ,并且共享内存的状态会变成dest(destroy)
  • 我们通过ipsc -m这个命令可以查看到当前被删除共享内存的信息,说明被操作系统内核,描述该共享内存的结构体没有被释放,但是共享内存使用的空间已经被释放了,所以,附加进程如果再次操作共享内存,则有崩溃的风险
    Linux—进程间通信—共享内存详解_第5张图片
  1. 共享内存被创建以后,一直存在于内核当中,直到被删除或者系统关闭,并且读取后,内容仍然在其共享内存当中。

你可能感兴趣的:(Linux)