网站建设后端工程师岗位职责,做网站网,阿里云网站开发服务器,wordpress模板在哪个目录下引言#xff1a;
北京时间#xff1a;2023/3/21/7:17#xff0c;这篇博客本来昨天晚上就能开始写的#xff0c;但是由于笔试强训的原因#xff0c;导致时间用在了做题上#xff0c;通过快2个小时的垂死挣扎#xff0c;我充分意识到了自己做题能力的缺陷和运用新知识的缺…引言
北京时间2023/3/21/7:17这篇博客本来昨天晚上就能开始写的但是由于笔试强训的原因导致时间用在了做题上通过快2个小时的垂死挣扎我充分意识到了自己做题能力的缺陷和运用新知识的缺陷所以我需要把重心给转移一下了以后做题才是我的头号目标虽然我在很久以前可能就说过这样的话但是这次我是认真的就算我做题不行但是我看代码还是行的所以我每天必看一些做题代码来加深自己对知识的运用希望不久之后能有所进步吧哪怕只是一丝丝所以今天我们就来学习上篇博客剩下的有关进程控制的内容和有关进程程序替换的知识吧 复习进程等待
昨天已经浅浅的了解了什么是进程等待进程等待的目的就是为了终止僵尸进程回收僵尸进程所占的资源并且获得进程的退出码和退出信号并且我们了解了进行进程等待的两个接口函数wait/waitpid通过这两个接口我们就可以去调用操作系统提供给我们的系统调用这样就可以利用系统调用的形式来完成进程等待了我们昨天已经知道使用wait接口就是用来等待一个进程的子进程并且有代码演示这里不多做理解昨天我们也了解了waitpid这个接口发现该接口有三个参数并且其中第一个参数pid它的作用和wait的参数差不多本质就是为了等待一个进程pid0等待的是该进程的子进程pid0等待的则是任意一个pid相等的进程和第二个参数status我们了解到该参数是一个位图结构的参数不单单是整形类型本质为位图结构就是为了可以同时从一个参数上获取退出码和退出信号两个码值第三个参数options就是用于判断子进程是否正常终止父进程是否继续等待的问题所以接下来我们就承接这上篇博客把剩下的有关位图结构也就是有关status参数的知识再深入学习一下如下
继续谈status
上篇博客我们了解到status是一个位图结构可以同时返回退出码和退出信号并且退出码是由32个比特位中的后16个比特位中的次第8位构成的退出信号是由最后7个比特位构成的core down先不谈所以按照这个逻辑此时我们想要拿到status中的退出信号和退出码是有办法的没错就是使用我们在C语言中所学的位运算的概念具体这里不多做讲解具体就是左移和右移左移以为表示的就是该值乘2右移一位表示的就是除2并且还涉及到了按位或、按位与、按位异或的知识如下图
通过上述的 status 8 0xFF、status 0x7F 此时我们就可以获得该进程的退出码和退出信号了但是要知道上述获取子进程退出码和退出信号的方式是我们自己通过位图结构的概念通过位运算获得的但是注意在Linux操作系统内部它本身是为我们提供了获取子进程退出码和退出信号的方式如下图
所以按照我们上述所说父进程就可以通过使用waitpid接口来调用系统调用从而获取子进程的退出码和退出信号但是具体在调用系统调用接口的时候本质上这些工作还是由我们的操作系统来完成了因为只有操作系统才有获取进程退出码和退出信号的资格所以此时就有一个问题就是父进程具体是如何通过操作系统来获取子进程的退出码和退出信号呢
首先明白无论是父进程还是子进程它们都是一个独立的进程所以每个进程都拥有自己的地址空间进程pcb、页表和物理内存等资源并且明白子进程pcb内不仅有从父进程pcb中继承的相关属性而且还有两个和子进程退出码和退出信号至关重要的属性 int exit_code int exit_signal 从该属性的名字就可以看出这两个子进程pcb属性代表的就是进程退出码和退出信号表示的仅仅就是两个整数而已 明白了这些之后此时就可以回答该问题了如下 当子进程执行完毕之时操作系统会将main函数对应的返回值写到该进程pcb的int exit_code当中如果该进程异常则将对应的退出信号写到该进程pcb的int exit_signal当中并且最后在进程退出之后操作系统会将该进程的pcb维护起来所以当该子进程pcb被操作系统维护起来之后此时父进程就可以通过调用系统接口 wait/waitpid 通过操作系统来去找到该退出进程对应的进程pcb可以找到子进程pcb的具体原理是因为父进程在调用waitpid接口的时候已经把子进程的pid告诉了父进程也就是传参的时候已经把进程子pid给给了waitpid接口所以最后通过子进程pid进而找到该子进程的pcb进而找到pcb中的该子进程的退出码 int exit_code 和退出信号 int exit_signal最后再利用waitpid中的第二个参数status输出型参数将退出码和退出信号返回给父进程当然也就是上述的ret_id变量
总父进程获取子进程的退出码和退出信号的本质就是通过操作系统读取子进程的内核数据结构pcb 并且有的同学非常的好奇就是有没有一种可能就是父进程在等待的时候子进程一直没有退出呢或者说父进程在等待的时候具体是在干什么呢 所以此时我们就借着上述问题来谈一谈什么是阻塞等待和非阻塞轮询等待
首先我们要明白当子进程没有退出的时候父进程在干什么呢 谈到这个此时又不得不谈谈waitpid的第三个参数options上篇博客我们说了这个参数的作用就是用于判断子进程是否正常终止父进程是否继续等待问题并且该参数我们默认给给的是一个叫 WNOHANG 的参数具体意思就是用于判断该子进程是否终止如果该子进程未终止那么此时waitpid()函数就返回0如果该子进程终止则返回该子进程的pid此时就可以很好的通过这第三个参数来判断一个进程的子进程是否处于终止状态所以明白了这点此时就可以明白父进程是可以通过该参数来控制自己的行为也就是上述所说的阻塞等待和非阻塞轮询等待
谈谈父进程的阻塞等待
从上述的知识我们可以知道如果waitpid()函数返回0表示的就是该子进程没有结束子进程没有结束那么父进程此时可以干什么呢首先第一种情况父进程一直在调用waitpid进行等待 此时的一直进行等待本质上表示的就是阻塞等待也就是表示父进程此时从本来的正常运行状态变成了一个阻塞状态变成了一个等待子进程的状态所以我们可以明白当父进程处于阻塞状态之时父进程是不在CPU的运行队列之中而是在某一个阻塞队列之中并且此时再深入理解还可以明白父进程处于阻塞等待之时子进程处于运行状态那么等子进程执行完之后呢父进程如何从阻塞状态重新变成运行状态来为子进程收尸呢 谈到这个问题此时就又涉及到了子进程的进程pcb在子进程pcb内部我们可以理解存在一个指向父进程的指针所以当子进程一但退出注意此时父进程肯定是不在运行队列而是在阻塞队列的此时子进程就可以利用pcb中指向父进程的指针重新找到父进程唤醒此时父进程检测到之后被唤醒就又会从阻塞状态变成运行状态然后被操作系统又重新链接到运行队列之中最后父进程继续执行 wait/waitpid最终就将子进程给回收
所以上述就是父进程阻塞等待全过程
谈谈父进程的非阻塞轮询等待
搞懂了上述父进程的阻塞等待此时就可以明白父进程肯定还有一种非阻塞等待毕竟我是父进程你是小子我才是老子我凭什么一定要等你呢所以此时还是同理当我们通过waitpid()函数的返回值判断出该子进程还没有结束时我们就可以让父进程不需要一直进行等待不需要一直处于阻塞状态具体代码如下 所以此时通过上述的代码我们就可以很好的理解什么是父进程的阻塞等待和非阻塞轮询等待了并且可以将其很好的抽象成一个生活中场景如下 场景一 周末出去玩李四打电话给张三问张三去不去此时张三说去但是要准备一下子进程未终止李四说好我等你父进程等待但是电话别挂阻塞等待 场景二 如法炮制还是周末出去玩李四打电话给张三问张三去不去张三还是去并且也还是需要准备一下此时李四还是说好但是此时李四却把电话给挂断了在电话挂断之后李四想了想也去准备了一下过了一会之后李四准备的差不多了就又打电话给张三张三却还是没有准备好此时李四就又把电话挂了又去准备东西了同理李四一直打电话问张三好了没有非阻塞轮询等待而张三却一直没好直到最后好了子进程终止 所以上述的两种情况李四给张三打电话表示的就是父进程使用waitpid()等待子进程第一种情况电话不挂表示的就是父进程处于阻塞队列这种情况也就是阻塞调用第二种情况表示我打完电话问完情况我们把电话挂掉此时表示的就是父进程不处于阻塞等待也就是表示该调用此时是属于非阻塞调用非阻塞调用的好处就是父进程可以干自己想干的事情例准备自己的东西
所以上述的两种场景就是父进程阻塞等待和非阻塞等待的两个现实生活抽象场景可以非常好的凸显出父进程等待的两种情况
总父进程可以通过参数进行判断然后来控制自己的行为也就是上述所说的阻塞等待和非阻塞轮询等待
总结进程控制的三个话题进程创建、进程等待、进程终止此时就算告一段落啦现在让我们呢一起开始新知识的学习吧
进程替换
搞定了上述的知识此时我们就进入今天的正菜什么是进程替换在弄懂什么是进程替换之前我们引入一个问题就是为什么要创建子进程所以我们要明白我们创建子进程的目的就是为了让子进程帮我执行某些特定的任务但是此时让子进程去执行某些代码的时候就会出现如下两种情况 1. 让子进程执行父进程的部分代码也就是一个可执行文件中的部分代码这些代码本质都是属于父进程 2. 子进程想要执行一个全新的属于自己的代码本质就是不想执行父进程的代码 所以碰到上述第二种情况此时就可以引出我们的新概念进程程序替换
如下图就是一个最简单的进程程序替换demo 所以使用execl接口的本质就是进行进程的切换让该可执行文件形成的进程去执行Linux操作系统中bin目录下的ls指令ls可执行文件也就是表明当我们使用了进程替换函数时我们可以在任意一个可执行文件中执行任意的指令本质是进程替换
总进程程序替换就是让一个进程去执行另一个在磁盘Linux操作系统下的bin目录当中的程序可执行文件把一个新的程序运行起来
程序替换的原理
首先明白创建一个进程该进程肯定是有对应的pcb、页表、地址空间和物理内存所以我们就从这些进程的必要条件入手来看看进程替换到底是什么如下图
从图中我们可以了解到以下知识 当前进程的代码等数据是需要通过页表映射到物理内存的特定区域所以当一个进程执行了部分代码后当其执行到了系统调用接口execl等……进程此时就会根据我所传入的程序的路径Linux操作系统下的bin目录和我要执行的程序的名称和选项“ls” “a”然后把磁盘当中通过对应的路径找到bin的其它的程序的代码和数据加载到内存最后用新程序的代码来替换我们原程序中的代码用新程序的数据来替换原程序中的数据这个过程不是在地址空间完成的是在物理内存中完成的所以总的来说 程序在替换时就相当于原进程的内核数据结构不变把原进程在物理内存中的代码和数据替换为新进程的代码和数据从磁盘中加载此时这个行为的发生就叫做程序替换。
并且要明白进程在进行程序替换的时候是没有创建新的进程的本质还是程序替换的本质。
并且此时明白可以进行进程程序替换的接口一共有7个此时我们已学其一剩下的6个都是同理只是在使用上不同而已所以我们今天浅浅的摸了一下程序替换就行了明天要晨跑今天博客就这样吧撤了
补充小知识点
fork函数的两个返回值浅显理解一个是父进程返回子进程的pid一个是子进程没有子进程所以返回0感兴趣的同学可以参看下面这个链接为什么fork有两个返回值
北京时间2023/3/21/22:45
总结像程序替换execl这样的系统接口等我们学到了文件操作和网络的时候我们就经常会谈到并且会用到更多所以革命还未胜利挑战任在继续加油吧少年