• IPC 进程间通信方式——共享内存


    共享内存

    • 共享内存区域是被多个进程共享的一部分物理内存。
    • 多个进程都可以把共享内存映射到自己的虚拟空间。所有用户空间的进程要操作共享内存,都要将其映射到自己的虚拟空间,通过映射的虚拟内存空间地址去操作共享内存,从而达到进程间的数据通信。
    • 共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容
    • 本身不提供同步机制,可通过信号量进行同步
    • 提升数据处理效率,一种效率最高的IPC机制

    共享内存属性信息

    struct shmid_ds{
        struct ipc_perm shm_perm;
        size_t shm_semsz;//共享内存大小   
        pid_t shm_lpid;//最后一次调用系统pid
        pid_t shm_cpid;//pid的创建者的id
        shmatt_t shm_nattch;//和共享内存成功映射的数量
        time_t shm_atime;//最后一个成功映射的时间
        time_t shm_dtime;//最后断开映射的时间
        time_t shm_ctime;//最后改变的时间
    }
    

    共享内存使用步骤

    • 使用shmget()函数创建共享内存
    • 使用shmat()函数映射共享内存,将这段创建的共享内存映射到具体的进程虚拟内存空间

    创建共享内存

    #include <sys/shm.h>
    itn shmget(key_t key,size_t size,int shmflag);
    //返回,成功返回内核中共享内存的表示iD,失败返回-1.
    
    • 参数
      • key:用户指定的共享内存键值
      • size:共享内存大小
      • shmflg:IPC_CREAT,IPC_EXCL等权限组合
    • erron
      • EINVAL(无效的内存段大小)
      • EEXIST(内存段已经存在,无法创建)
      • EIDRM(内存段已经被删除)
      • ENOENT(内存段不存在)
      • EACCES(权限不够)
      • ENOMEM(没有足够内存创建内存段)

    共享内存控制

    #include<sys/shm.h>
    int shmctl(int shmid,int cmd,struct shmid_ds *buf);
    
    • 参数
      • shmid:共享内存ID
      • buf:共享内存属性指针
      • cmd
        • IPC_STAT 获取共享内存段属性
        • IPC_SET 设置共享内存段属性
        • IPC_RMID 删除共享内存段
        • SHM_LOCK 锁定共享内存段页面
        • SHM_UNLOCK 解锁锁定

    共享内存映射和解除

    #include<sys/shm.h>
    void shmat(int shmid,char *shmaddr,int shmflg);
    int shmdt(char  *shmaddr);
    //失败返回-1
    
    • 参数
      • shmid:共享内存ID
      • shmaddr:映射到进程虚拟内存空间的地址,系统自动分配
      • shmflg:弱shmaddr为0,shmflag也是0
        • SHM_RND
        • SHMLBA 地址为2的次方
        • SHM_RDONLY 只读方式连接
    • errno
      • EINVAL 无效的IPC ID值或无效的地址
      • ENOMEM 没有足够的内存
      • EACCES 权限不够
    • 子进程不继承父进程创建的共享内存,大家是共享的,子进程继承父进程映射的地址。

    案例:
    通过共享内存实现进程间通信

    #include <sys/shm.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "tell.h"
    
    int main(void)
    {
        //创建共享内存
        int shmid;
        if((shmid=shmget(IPC_PRIVATE,1023,
                    IPC_CREAT|IPC_EXCL|0777))<0)
        {
            perror("shmget error");
            exit(1);
        }
    
        pid_t pid;
        init();//初始化管道
        if((pid=fork())<0)
        {
            perror("fork error");
            exit(1);
        }else if(pid>0)
        {
            //parent process
            //进行共享内存的映射
            int *pi=(int*)shmat(shmid,0,0);
            if(pi==(int*)-1)
            {
                perror("shmat error");
                exit(1);
            }
            //往共享内存中写入数据
            *pi=100;
            *(pi+1)=200;
            //操作完毕,解除映射
            shmdt(pi);
            //通知子进程去读取数据
            notify_pipe();
            destory_pipe();
            wait(0);
        }else
        {
            //child process
            //子进程阻塞,都带父进程往共享内存写入数据
            wait_pipe();
            //子进程从共享内存中读取数据
            //子进程进行共享内存的映射
            int *pi=(int*)shmat(shmid,0,0);
            if(pi==(int*)-1)
            {
                perror("shmat error");
                exit(1);
            }
            printf("start:%d,end:%d
    ",*pi,*(pi+1));
            //读取完毕解除映射
            shmdt(pi);
            //删除共享内存
            shmctl(shmid,IPC_RMID,NULL);
    
            destory_pipe();
            
        }
    }
    
  • 相关阅读:
    软件工程作业团队作业No.1
    软件工程作业No.5
    软件工程作业No.4
    软件工程作业No.3
    软件工程作业No.2
    java 读写yml文件,修改文件内容保持原格式
    oracle 相关
    git基础从创建仓库开始
    oracle安装过程问题记录
    Java 实现小工具读取文件有多少个单词
  • 原文地址:https://www.cnblogs.com/SeekHit/p/6724274.html
Copyright © 2020-2023  润新知