操作系统:06 进程通信

news/2024/11/28 3:32:03/

1 基本概念

        进程间通信是指两个或多个进程之间交互数据的过程,因为进程之间是相互独立的,为了协同工作必须进行进程间交互数据

2 进程间通信的分类

2.1 简单的进程间通信:

        信号(携带附加数据)、文件、命令行参数、环境变量表

2.2 传统的进程间通信:

        管道文件(有名管道、匿名管道)

2.3 XSI的进程间通信:

        共享内存、消息队列、信号量

2.4 网络的进程间通信:

        套接字技术Socket

3 传统的进程间通信:管道文件

        管道是UNIX系统中最古老的进程间通信方式,古老意味着所有系统都支持,早期的管道文件支持半双工通信,现在有些系统的管道支持全双工

        管道是一种特殊的文件,它的数据在文件中是流动的,读取之后就消失,如果文件中没有数据可读取时读取操作会阻塞

3.1 有名管道

        基于有文件名的管道文件的通信

3.1.1通信编程模型:

        进程A                   进程B

      创建管道文件           ...

      打开文件             打开文件

      写数据                  读数据

      关闭管道             关闭管道

      删除管道文件           ...

3.1.2创建有名管道:

命令: mkfifo filename

函数:

    int mkfifo(const char *pathname, mode_t mode);

        功能:创建有名管道文件

        pathname:管道文件的路径

        mode:文件权限

  3.2匿名管道:

        注意:只适合通过fork创建的父子进程之间通信

    int pipe(int pipefd[2]);

        功能:创建一个匿名管道文件

        通过参数pipefd,返回该匿名管道文件的读文件描述符和写文件描述符

        pipefd:存储读写fd的数组,输出型参数

        pipefd[0] 用于读  pipefd[1] 用于写

3.2.1 匿名管道的编程模型:

            父进程                     子进程

   创建获取匿名管道         ...

        创建子进程              共享一对fd

           关闭读                     关闭写

           写数据                     读数据

           关闭写                      关闭读

3.2.2 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键值,就有意义了

4 共享内存

4.1 基本特点

        两个或多个进程之间共享一块由内核负责维护的内存,该段内存可以与多个不同的进程的虚拟内存建立映射

        优点:操作简单,不需要读写磁盘、不需要复制,最快的一种XSI机制

        缺点:需要考虑同步访问的问题,一般使用信号解决

4.2 使用

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

    功能:创建/获取共享内存

    key:IPC键值 ftok给

    size:共享内存的大小,只有获取共享内存时此参数无意义就设置为0

    shmflg:

        IPC_CREAT 创建共享内存,已存在时则获取

        IPC_EXCL  共享内存已存在时则返回失败

        如果是获取直接赋0

        注意:当创建共享内存时,需要额外提供该段共享内存的权限码,

            例如shmget(xx,4096,IPC_CREAT|0644)

    返回值:IPC标识符,是创建/获取得到的共享内存的标识,错误会返回-1(只要不是-1就代表创建/获取成功)

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

    shmid:IPC标识符

    shmaddr:想要映射的虚拟内存首地址,如果为NULL时由操作系统自动选择

    shmfig:

        SHM_RND 当shmaddr不为NULL时才有效,标识从shmaddr开始取内存页的整数倍进行映射,提高内存读写效率

        SHM_RDONLY  以只读方式映射共享内存

    返回值:成功映射后的内存首地址,映射失败返回0xFFFFFFFF(-1)

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

    功能:删除/控制共享内存

    shmid:IPC标识符

    cmd:

        IPC_STAT    获取共享内存的属性数据  buf输出型参数(获取到的属性数据存储到buf里)

        IPC_SET     设置共享内存的属性数据  buf输入性参数(使用者将要设置的属性数据存到buf里)

        IPC_RMID    删除共享内存(IPC也会删掉,统统删光)

    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;    //创建者进程号PID

        pid_t           shm_lpid;    //最后取消映射的进程号PID

        shmatt_t        shm_nattch;  //当前映射次数

    };

    int shmdt(const void *shmaddr);

    功能:取消虚拟内存与共享内存的映射

    shmaddr:虚拟内存的首地址

4.3 编程模型

            进程A                                    进程B

         创建共享内存                     获取共享内存

         映射共享内存                     映射共享内存

         写数据并通知其它进程     接到通知后读数据

         接到通知后读数据         写数据并通知其它进程

         取消映射                               取消映射

         删除共享内存                             ...  

5 消息队列

5.1 基础概念

        由内核负责维护管理的数据链表结构,通过消息类型来对应的收发数据

5.2 使用

    int msgget(key_t key, int msgflg);

    功能:创建/获取消息队列

    key:IPC键值 ftok给

    shmflg:

        IPC_CREAT 创建消息队列,已存在时则获取

        IPC_EXCL  消息队列已存在时则返回失败

        如果是获取直接赋0

        注意:当创建消息队列时,需要额外提供该消息队列的权限码,

    返回值:IPC标识符,是创建/获取得到的共享内存的标识,错误会返回-1(只要不是-1就代表创建/获取成功)

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

    功能:向消息队列发送消息包

    msqid:IPC标识符

    msgp:消息包结构首地址

            struct msgbuf {

               long mtype;       //消息类型,必须>0

               char mtext[n];    //消息数据

           };

    msgsz:消息数据的字节数即mtext的字节数

    msgflg:

        0   阻塞发送

        IPC_NOWAIT  当消息队列满时,立即结束并返回,

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

    功能:从消息队列中接收对应的消息包中的数据

    msqid:IPC标识符

    msgp:存储读取到的消息包结构首地址

        struct msgbuf {

            long mtype;       //消息类型,必须>0

            char mtext[n];    //消息数据

        };

    msgsz:消息包结构体字节数

    msgtyp:要接收的消息类型几号

        0   读取当前消息队列中的第一条消息包  

        >0  读取消息类型为msgtyp的消息包

        <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:

        消息队列属性结构体

5.3 编程模型

       进程A                               进程B

    创建消息队列                 获取消息队列

      发送消息                         接收消息

    接收不同的消息包       发送不同的消息包

      删除消息                              ...

6 信号量

6.1基本特点

        由内核来维护共存给若干个进程的“全局变量”,用于记录共享资源的数量,限制进程对共享资源的访问

        信号量是一种数据操作锁,本身不具备完整的数据通信交换功能而是通过控制其他的通信资源来更好地实现进程间通信

    1、如果信号量的值>0,说明可以使用资源,需要先信号量-1.然后再使用

    2、如果信号量的值=0,说明没有资源可以使用,此时进程进入休眠,直到信号量的值>0,进程会被唤醒,执行步骤1

    3、当资源使用完毕后,先把信号量的值+1,然后内核会唤醒正在休眠的进程

    int semget(key_t key,int nsems,int semflg)

    功能:创建/获取信号量

    key:IPC键值

    nsems:信号量整体个数,一般写1

    semflg:

    返回值:IPC标识符

    int semop(int semid,struct sembuf *sops,size_t nsops);

    功能:对信号量的值进行操作

    semid:标识符


http://www.ppmy.cn/news/62878.html

相关文章

Java线程池及其实现原理

线程池概述 线程池&#xff08;Thread Pool&#xff09;是一种基于池化思想管理线程的工具&#xff0c;经常出现在多线程服务器中&#xff0c;如MySQL。 线程过多会带来额外的开销&#xff0c;其中包括创建销毁线程的开销、调度线程的开销等等&#xff0c;同时也降低了计算机…

Vue3 watch 监听对象数组中对象的特定属性

在 Vue 3 中&#xff0c;可以使用 watch 函数来监听对象数组中对象的特定属性。可以通过在回调函数中遍历数组来检查对象的特定属性是否发生变化&#xff0c;并在变化发生时执行相应的操作。 一、监听对象的特定属性 例如&#xff0c;假设有一个名为 items 的对象数组&#x…

欧科云链OKLink:2023年4月安全事件盘点

一、基本信息 2023年4月安全事件共造约6000万美金的损失&#xff0c;与上个月相比&#xff0c;损失金额有所降落&#xff0c;但安全事件数量依旧不减。其中&#xff0c;Yearn Finance因参数配置错误&#xff0c;导致了1000多万美金的损失。同时&#xff0c;有一些已经出现过的…

platform总线五级匹配解析

代码来源&#xff1a;开源linux内核linux-6.2.9 platform总线设备与驱动的匹配 对于device和driver无论哪个创建都会尝试主动寻找对方进行绑定&#xff0c;而platform bus总线的匹配原则如上面的代码所示&#xff0c;共有五级匹配&#xff0c;这里进行详细解析下&#xff1a; …

CSAPP第九章 虚拟内存

概述 程序是存放在虚拟地址空间中&#xff0c;运行是在物理空间中&#xff0c;如何进行转换是虚拟内存需要研究的问题。 完成逻辑地址到虚拟地址再从虚拟地址到逻辑地址映射的机构叫MMU 两个部件 段式管理和页式管理 之前有提到&#xff0c;cache的管理是通过cache映射表&…

SIM800C模块AT指令测试(三)语音功能相关

1. 紧急呼叫操作 每个国家区域的紧急号码不同&#xff0c;客户可通过AT指令设置需要的号码&#xff0c;最多可以设置11个。 ATCEMNL? CEMNL: (0-1),(1-11),("0"-"999")... OK ATCEMNL1,3,“112”,“000”,“911” // 设置紧急号码 OK AT…

块状链表实现BigString大字符串操作(golang)

前言 块状链表是介于链表和数组之间的数据结构&#xff0c;能够在 O ( n ) O(\sqrt{n}) O(n ​)时间内完成插入、删除、访问操作。 数据结构如图所示。假设最大容量为 n n n, 则它有一个长度为 s n s\sqrt{n} sn ​的链表。链表中每个结点是一个长度为 2 n 2 \times \sqrt{…

配置本地Angular环境并使用VsCode调试Angular前端项目

配置本地Angular环境并使用VsCode调试Angular前端项目 配置本地Angular环境部署Node.Js本地环境配置一下环境变量 使用vscode调试Angular安装vscode 配置本地Angular环境 部署Node.Js本地环境 1 从官网下载node.js, 本文为(v16.13.0) 下载地址: https://nodejs.org/dist/v16.…