文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Linux-进程间通信

2023-08-19 08:29

关注

进程间通信目的

进程间通信发展

进程间通信分类

管道

System V IPC

POSIX IPC

从一个进程连接到另一个进程的一个数据流称为一个“管道”

在这里插入图片描述
注:

补充:

匿名管道

  • 匿名管道供具有血缘关系的进程,进行进程间通信(常见于父子进程)

在这里插入图片描述

#include 功能:创建一无名管道原型int pipe(int fd[2]);参数fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端返回值:成功返回0,失败返回错误代码RETURN VALUE       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

用fork来共享管道原理

在这里插入图片描述

注:

站在文件描述符角度-深度理解管道

站在内核角度-管道本质
在这里插入图片描述

代码实列:

#include#include#include#include #include int main(){    int pipe_fd[2]={0};    if(pipe(pipe_fd)<0)    {        perror("pipe");        return 1;    }    printf("%d,%d\n",pipe_fd[0],pipe_fd[1]);    pid_t id=fork();    if(id<0)    {        perror("fork");        return 2;    }    else if(id==0)    {        close(pipe_fd[0]);        const char* msg="hello parent,i am child";        int count=5;        while(count)        {            write(pipe_fd[1],msg,strlen(msg));            sleep(1);            count--;        }        close(pipe_fd[1]);        exit(0);    }    else     {        close(pipe_fd[1]);        char buffer[64];        while(1)        {            ssize_t size=read(pipe_fd[0],buffer,sizeof(buffer)-1);            if(size>0)            {                buffer[size]=0;                printf("parent get messge from child# %s\n",buffer);            }            else if(size==0)            {                printf("pipe file close,child quit!\n");                break;            }            else             {                perror("read");                break;            }        }        int status=0;        if(waitpid(id,&status,0)>0)        {            printf("child quit,wait success!\n");        }        close(pipe_fd[0]);    }    return 0;}

匿名管道特点

注意:读端从管道成功读取数据之后管道里面的数据会设置成无效

补充:

  • 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
  • 管道提供流式服务
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  • 一般而言,内核会对管道操作进行同步与互斥
  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
    在这里插入图片描述

管道自带同步机制检验:
在这里插入图片描述

匿名管道读写规则

在这里插入图片描述
在这里插入图片描述
补充:
在这里插入图片描述

在这里插入图片描述
注:读取端关闭,一直写是毫无意义的,本质就是在浪费系统资源,写进程会立刻被OS终止掉(通过发送信号的方式),获取终止信号可以由waitpid获取

管道大小的检验:
在这里插入图片描述
结论:管道大小为64KB

注:用man 7 pipe查看PIPE_BUF

总结:

补充:
在这里插入图片描述
进程退出,曾经打开的文件也会被关掉。管道也是文件,管道的生命周期是随进程的

命名管道

  • 不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
  • 命名管道是一种特殊类型的文件

注:

创建一个命名管道

  1. 命令行中创建
 mkfifo filename

在这里插入图片描述
在这里插入图片描述

  1. 程序里创建
int mkfifo(const char *filename,mode_t mode);

在这里插入图片描述

注:用man mkfifo查看命令行中的mkfifo;用man 3 mkfifo查看程序中的mkfifo

匿名管道与命名管道的区别:

总结:匿名管道与命名管道只是进程间的关系的问题(匿名管道进程间有血缘关系、命名管道进程间毫无关系),此外匿名管道有的管道特点命名管道也都有

命名管道的打开规则

用命名管道实现server&client通信

在这里插入图片描述

总结:

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据

共享内存

在这里插入图片描述

注:

  • system V共享内存达到通信的步骤:
    1. 申请共享内存
    1. 进程A和进程B分别挂接对应的共享内存到自己的地址空间(共享内存)
    1. 双方就看到了同一份资源,既可以进行正常通信了

注:上述的这些步骤,有对应的系统调用接口,给提供服务

共享内存函数

shmget函数

功能:用来创建共享内存原型 int shmget(key_t key, size_t size, int shmflg);参数 key:这个共享内存段名字 size:共享内存大小 shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

在这里插入图片描述

在这里插入图片描述
注:

在这里插入图片描述

注:nattch指的是与当前共享内存关联的进程的个数

补充:
在这里插入图片描述

注意:“dest”状态
Linux下删除任何内容,都会先检查一下这个内容的引用计数(就是文件的使用数,n个进程使用,引用计数为n)。若引用计数为0,就会真正的删除该内容(这里就是删除共享内存)。不为0,表示仍有进程使用,则正在使用的进程可以正常使用,直至引用计数降为0后,系统才会将该内容真正意义上的删除掉。
对这里用共享内存来说同理,显示“dest”是表示该共享内存已经被删除但有进程还在使用它。这时操作系统将共享内存的mode标记为SHM_DEST,key标记为0x00000000,并对外显示status为“dest”。当用户调用shmctl的IPC_RMID时,系统会先查看这个共享内存的引用计数,如果引用计数为0,就会销毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。

在这里插入图片描述

在这里插入图片描述
shmctl函数

功能:用于控制共享内存原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);参数 shmid:由shmget返回的共享内存标识码 cmd:将要采取的动作(有三个可取值) buf:指向一个保存着共享内存的模式状态和访问权限的数据结构返回值:成功返回0;失败返回-1

在这里插入图片描述
在这里插入图片描述

shmat函数

功能:将共享内存段连接到进程地址空间原型 void *shmat(int shmid, const void *shmaddr, int shmflg);参数 shmid: 共享内存标识 shmaddr:指定连接的地址 shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

在这里插入图片描述

说明:

  • shmaddr为NULL,核心自动选择一个地址
  • shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
  • shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
  • shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

在这里插入图片描述
shmdt函数

功能:将共享内存段与当前进程脱离原型 int shmdt(const void *shmaddr);参数 shmaddr: 由shmat所返回的指针返回值:成功返回0;失败返回-1注意:将共享内存段与当前进程脱离不等于删除共享内存段

在这里插入图片描述
在这里插入图片描述

注:System V进程间通信不需要用系统调用函数read、write的方式来实现通信

system V共享内存的特点

在这里插入图片描述
总结:

  1. 共享内存的生命周期随操作系统(OS)(进程退出,共享内存不销毁)
  2. 共享内存不提供任何同步与互斥的操作,双方彼此独立(进程间通信不考虑读写端问题)
  3. 共享内存是所有的进程间通信中,速度最快的(因为进程间通信不需要使用read、write等函数调用,以及写时拷贝次数少(不需要拷贝到缓冲区))

补充:

  • 共享内存的大小,系统在分配shm的时候,是按照4KB为基本单位的(下图中的共享内存大小为4097,在OS中分配为4096+4096其中4095大小的空间会浪费)在这里插入图片描述
  • key:是一个用户层的唯一键值,核心作用是为了区分“唯一性”,不能用来进行IPC资源的操作(key类比于inode号)
  • shmid:是一个系统给我们返回的IPC资源标识符,用来进行操作IPC资源(shmid类比于文件的fd)
    在这里插入图片描述
  • 用make和makefile编译多个源文件
    在这里插入图片描述

共享内存数据结构

struct shmid_ds { struct ipc_perm shm_perm;  int shm_segsz;  __kernel_time_t shm_atime;  __kernel_time_t shm_dtime;  __kernel_time_t shm_ctime;  __kernel_ipc_pid_t shm_cpid;  __kernel_ipc_pid_t shm_lpid;  unsigned short shm_nattch;  unsigned short shm_unused;  void *shm_unused2;  void *shm_unused3; };

在这里插入图片描述

注:
IPC资源在内核中是数组维护的(是通过类似于C++中的切片的方式用ipc_perm来找到共享内存、消息队列、信号量)
在这里插入图片描述

补充:

Linux ipcs命令与ipcrm命令的用法详解

在这里插入图片描述

消息队列数据结构

在这里插入图片描述

  1. 让进程看到同一份资源(内存空间)——临界资源
  2. 进程内的所有的代码,不是全部的代码都是访问临界资源,而是只有一部分在访问,可能造成数据不一致问题的是这部分少量的代码——临界区
  3. 为了避免数据不一致,保护临界资源,需要对临界区代码进行某种保护(互斥)
  4. 互斥:一部分空间任何时候,有且只有一个进程在进行访问,串行化的执行(eg:锁、二元信号量)
  5. 加锁和解锁是有对应的代码的。本质是对临界去进行加锁和解锁,完成互斥操作

在这里插入图片描述

信号量的数据结构

在这里插入图片描述

补充:

  • 原子性(感性认识):要么做了,要么没做
  • 信号量:本质是一个计数器。用来描述临界资源中资源数目的计数器
  • PV原语:
    1. P操作:申请信号量(成功:一定有一个临界资源给你使用)
    1. V操作:释放信号量
  • 多个信号量不能操作同一个count值(信号量不等于count)
  • 信号量可以保护临界资源的安全性(操作计数器时是有多条语句构成,有可能多份配资源出去,不是原子性的)
  • 信号量本身就是一个临界资源,要保护其他临界资源,先得保护自己的安全(PV操作是原子的)
  • 信号量在多进程环境下,可以通过semget,semctl,ftok()等系统接口来保证信号量被多个进程看到
  • 如果信号量的计数器的值是:1 (1、0:二元信号量(互斥语义))

在这里插入图片描述

在这里插入图片描述

来源地址:https://blog.csdn.net/AI_ELF/article/details/123136781

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯