Day07 进程间通信

进程间通信
基本概念:
    什么是进程间通信:是指两个或多个进程之间交互数据的过程,因为进程之间是相互独立的,为了协同工作必须进行进程间交互数据
进程间通信的分类:
    简单的进程间通信:
        信号(携带附加数据)、文件、命令行参数、环境变量表
    传统的进程间通信:
        管道文件(有名管道、匿名管道)
    XSI的进程间通信:
        共享内存、消息队列、信号量
    网络的进程间通信:
        套接字技术Socket

传统的进程间通信:管道文件
    管道是UNIX系统中最古老的进程间通信方式,古老意味着所有系统都支持,早期的管道文件支持半双工通信,现在有些系统的管道支持全双工
    管道是一种特殊的文件,它的数据在文件中是流动的,读取之后就消失,如果文件中没有数据可读取时读取操作会阻塞

    有名管道:
        基于有文件名的管道文件的通信
    通信编程模型:
        进程A                   进程B
      创建管道文件               ...
      打开文件                  打开文件
      写数据                    读数据
      关闭管道                  关闭管道
      删除管道文件               ...
    
    创建有名管道:
        1、命令: mkfifo filename
        2、函数:
        int mkfifo(const char *pathname, mode_t mode);
        功能:创建有名管道文件
        pathname:管道文件的路径
        mode:文件权限
    
    匿名管道:
        注意:只适合通过fork创建的父子进程之间通信
        int pipe(int pipefd[2]);
        功能:创建一个匿名管道文件
        通过参数pipefd,返回该匿名管道文件的读文件描述符和写文件描述符
        pipefd:存储读写fd的数组,输出型参数
        pipefd[0] 用于读  pipefd[1] 用于写

        匿名管道的编程模型:
            父进程              子进程
         创建获取匿名管道         ... 
           创建子进程          共享一对fd
           关闭读               关闭写
           写数据               读数据
           关闭写               关闭读

XSI进程间通信:
    X/open公司制定用于进程间通信的系统(S)接口(I)规范
    XSI进程间通信都需要借助系统内核完成,需要创建内核对象来进行操作,内核对象以整数形式提供给调用者使用,类似于文件描述符\文件指针作为标识符存在,也叫做IPC标识符
    文件描述符\文件指针需要借助唯一的文件名进行建立,IPC标识符的创建需要借助IPC键值(整数),如果想要创建不同的IPC标识符,需要一个独一无二的IPC键值(别人也没用过)

    key_t ftok(const char *pathname, int proj_id);
    功能:计算出一个IPC键值
    pathname:项目路径
    proj_id:项目编号
    返回值:根据路径+编号计算出一个IPC键值
    注意:项目路径必须是有效路径,否则如果为非法路径,无论两个参数是否相同,计算出来的IPC键值一定相同,那就没意义了
    如果是有效路径,只要两个参数出现一个不同,那么就会计算出不相同的IPC键值,就有意义了

共享内存:
    基本特点:
        两个或多个进程之间共享一块由内核负责维护的内存,该段内存可以与多个不同的进程的虚拟内存建立映射
        优点:操作简单,不需要读写磁盘、不需要复制,最快的一种XSI机制
        缺点:需要考虑同步访问的问题,一般使用信号解决
    
    int shmget(key_t key, size_t size, int shmflg);
    功能:创建/获取共享内存
    key:IPC键值
    size:共享内存的大小,获取共享内存时此参数无意义就设置为0
    shmflg:
        IPC_CREAT   创建共享内存,已存在时则获取
        IPC_EXCL    共享内存已存在时则返回失败
        如果是获取直接赋0
        注意:当创建共享内存时,需要额外提供该段内存的权限码
            例如:shmget(xx,4096,IPC_CREAT|0666);
    返回值:IPC标识符,是创建\获取得到的共享内存的标识,错误返回-1

    void *shmat(int shmid,const void *shmaddr,int shmflg);
    功能:虚拟内存与共享内存建立映射关系
    shmid:IPC标识符
    shmaddr:想要映射的虚拟内存首地址,如果为NULL时由操作系统自动选择
    shmflg:
        SHM_RND   当shmaddr不为NULL时才有效,表示从shmaddr开始取内存页的整数倍进行映射,提高内存读写效率
        SHM_RDONLY  以只读方式映射共享内存
    返回值:成功映射后的内存首地址,失败返回0xFFFFFFFF
    
    int shmdt(const void *shmaddr);
    功能:取消虚拟内存与共享内存的映射
    shmaddr:虚拟内存的首地址

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    功能:删除/控制共享内存
    shmid:IPC标识符
    cmd:
        IPC_STAT    获取共享内存的属性数据 buf输出型参数
        IPC_SET     设置共享内存的属性数据 buf输入型参数
        IPC_RMID    删除共享内存          buf无意义NULL
    struct shmid_ds {
        struct ipc_perm shm_perm; // 所有者的相关信息
        size_t          shm_segsz;// 共享内存字节数
        time_t          shm_atime; //最后映射时间
        time_t          shm_dtime; //最后取消映射时间
        time_t          shm_ctime; //最后修改时间
        pid_t           shm_cpid;  //创建者的进程ID
        pid_t           shm_lpid;  //最后取消映射的进程ID
        shmatt_t        shm_nattch; //当前映射的次数
        ...
    };
        编程模型:
            进程A                   进程B
         创建共享内存           获取共享内存
         映射共享内存           映射共享内存
         写数据并通知其它进程   接到通知后读数据
         接到通知后读数据     写数据并通知其它进程
         取消映射               取消映射
         删除共享内存             ...   

消息队列:
    基础概念:由内核负责维护管理的数据链表,通过消息类型来对应地收发数据
    int msgget(key_t key, int msgflg);
    功能:创建/获取消息队列
    key:IPC键值
    msgflg:
        IPC_CREAT   创建消息队列,已存在时则获取
        IPC_EXCL    消息队列已存在时则返回失败
        如果是获取直接赋0
        注意:当创建消息队列时,需要额外提供消息队列的权限码
    返回值:IPC标识符,是创建\获取得到的共享内存的标识,错误返回-1

    int msgsnd(int msqid,const void *msgp,size_t msgsz, int msgflg);
    功能:向消息队列发送消息包
    msqid:IPC标识符
    msgp:消息包结构体首地址
        struct msgbuf {
            long mtype;     //  消息类型
            char mtext[n];  //  数据
        };
    msgsz:数据的字节数,不包含消息类型字节数
    msgflg:
        0   阻塞发送 一般写0
        IPC_NOWAIT  当消息队列满时,立即结束并返回

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    功能:从消息队列中接收对应的消息包中的数据
    msqid:IPC标识符
    msgp:存储读取到的消息包结构体首地址
    msgsz:消息包结构体的字节数
    msgtyp:要接收的消息类型
        >0    读取消息类型为msgtyp的消息包
        == 0  读取消息队列中的第一条消息包
        <0    读取消息类型小于abs(msgtyp)的消息包,如果有多个则读取消息类型最小值的消息包
    msgflg:一般写0
        IPC_NOWAIT如果没有符合的消息包,则立即返回不阻塞    
        MSG_EXCEPT 如果msgtyp>0,则读取第一个值不等于msgtyp的消息包
        MSG_NOERROR 如果不包含此标志,实际消息包的字节数>msgtyp时会返回错误并不读取,如果包含,则不报错并只读取前msgtyp个字节
    
    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    功能:删除\控制消息队列
    shmid:IPC标识符
    cmd:
        IPC_STAT    获取消息队列的属性数据 buf输出型参数
        IPC_SET     设置消息队列的属性数据 buf输入型参数
        IPC_RMID    删除消息队列          buf无意义NULL
    buf:
        消息队列属性结构体

    编程模型:
        进程A                   进程B
      创建消息队列              获取消息队列
      发送消息                  接收消息
      接收消息                  发送消息
      删除消息队列

信号量:
    基本特点:由内核来维护共享给若干个进程的"全局变量",用于记录共享资源的数量,限制进程对共享资源的访问
    信号量是一种数据操作锁,本身不具备完整的数据通信交换功能而是通过控制其他的通信资源来更好地实现进程间通信
    1、如果信号量的值大于0,说明可以使用资源,需要先信号量-1,然后再使用
    2、如果信号量的值等于0,说明没有资源可以使用,此时进程进入休眠,直到信号量的值>0,进程会被唤醒,执行步骤1
    3、当资源使用完毕,先把信号量的值+1,然后内核会唤醒正在休眠的进程

    int semget(key_t key, int nsems, int semflg);
    功能:创建/获取信号量
    key:同上
    nsems:信号量的个数,一般写1
    semflg:同上
    返回值:IPC标识符

    int semop(int semid,struct sembuf *sops,size_t nsops);
    功能:对信号量的值进行加减操作
    semid:IPC标识符
    sops:
        struct sembuf{
        unsigned short sem_num;  //信号量数组下标,一般写0
        short          sem_op;   
                1   信号量的值+1
                -1  只用信号量,如果值为0,则阻塞休眠
                0   等待信号量的值为0
        short          sem_flg; 
            IPC_NOWAIT  不阻塞
            SEM_UNDO    如果进程终止后没有还信号量,系统会自动还
        }
    nsops:表示sops指针指向多少个结构体,每个结构体表示对某一个信号量进行加减操作,一般写1

    int semctl(int semid, int semnum, int cmd, ...);
    功能:删除/控制信号量
    semid:IPC标识符
    semnum:第几个信号量,下标从0开始
    cmd:
        IPC_STAT    获取信号量的属性数据 
        IPC_SET     设置信号量的属性数据 
        IPC_RMID    删除信号量 
        GETVAL      通过返回值获取某个信号量的值  
        GETALL      获取所有信号量的值
        SETVAL      设置某个信号量的值(主要是值)  
        SETALL      设置所有信号量的值
        GETNCNT     获取等待减信号的进程的数量  -1  
        GETZCNT     获取等待信号量为0的进程数量 0

    union semun {
        int         val;    // 用于设置某个信号量的值
        struct semid_ds *buf;  // 用户设置或获取属性
        unsigned short  *array;  // 用于批量设置\获取信号量的值
    };




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值