Linux操作系统关于进程的控制


一、✔进程创建

1.再谈fork函数

fork是Linux中非常重要的函数,它能够从已经存在的进程中创建一个新的进程,新创建的进程叫做子进程,原有的进程叫做父进程。
头文件:<unistd.h>
返回值:子进程返回0,父进程返回子进程的pid,当子进程创建失败时返回-1

fork的具体介绍在上一篇博客里写了,可以点击链接查看

当我们的进程调用fork函数以后,内核会为我们做这几件事:

  • 分配新的内存块和内核数据结构给子进程(task_struct、mm_struct、页表)
  • 将父进程部分数据结构的内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork准备返回时,开始调度器调度

在这里插入图片描述

所以,fork函数之前,父进程是独立执行的,fork函数之后,父进程和子进程两个执行流分别执行。
注意:fork之后,谁先执行完全由调度器决定

我们可以写一个简单的代码来简单地验证一下fork函数前后的变化:
在这里插入图片描述

我们运行程序查看结果:
我们可以看到在fork函数之前,只有父进程一个进程在执行;在fork函数之后,父进程和子进程分别执行。
在这里插入图片描述

fork函数创建子进程以后,子进程将共享父进程的代码,这里的共享父进程的代码虽然看起来像是子进程只共享父进程在fork函数之后的所有代码,但实际上子进程是共享父进程的所有代码。只不过子进程只能从fork函数之后开始执行。

为什么刚创建出的子进程就能够知道父进程的代码执行到哪里了呢?
答:原因是在CPU中有一种寄存器叫作eip(程序计数器),也有的地方叫作PC指针,这个寄存器能够保存进程当前正在执行指令的下一条指令。而当父进程创建出子进程以后,父进程的eip程序计数器会被拷贝给子进程,子进程便知道父进程接下来要执行的指令是什么了。

2.写时拷贝

在fork函数成功创建子进程后,通常情况下父子进程代码是共享的,如果父子进程都不写入或者修改数据的情况下,数据也是共享的。当任意一方试图写入或修改数据时,操作系统便以写时拷贝的方式拷贝一份副本。(具体见下图)

在这里插入图片描述

为什么要有写时拷贝呢?难道不可以在创建子进程的时候就直接拷贝父进程的数据嘛?
答:在创建子进程的时候就把父子进程分开,这个方法是可以实现的。但是我们之所以不选择这个方法,是因为该方法并不是最优的。为什么要有写时拷贝,我们先来看看其他方案的缺点:

  1. 首先,如果在创建子进程的时候就将父子进程的数据分离开,父进程的数据子进程不一定会全部使用,即便全部使用了,也不一定全部写入,所以就会有浪费空间的可能性。
  2. 除此之外,最理想的方案是只将会被父子修改的数据进行分离拷贝,不需要修改的数据父子进程共享即可。但这种方案从技术角度实现复杂。

所以最终采用写时拷贝!也就是只有真正需要修改的时候才拷贝,这就是延迟拷贝策略。

二、✔进程终止

1.进程终止的场景

关于进程的终止,我们必须要有正确的认识,首先我们要回答下面的几个问题:在我们写代码的时候,main函数都会有一个返回值,我们一般返回值写的是0,那么这个返回值是给谁返回的?这个返回值为什么是0?可以是其他值嘛?

要回答上面的问题,我们首先来认识一下进程退出的场景:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

因此,我们每一个程序的main函数会有返回值,是因为在进程代码跑完的时候,父进程需要这个返回值来判断进程的运行结果,如果返回值是0,则表示代码跑完结果正确,非零则表示失败了。
这个返回值就是“进程退出码”!进程退出码表征了进程退出的信息。

我们可以来总结一下上面问题的答案:

  1. main函数的返回值叫做进程退出码,表征进程退出的信息
  2. 这个返回值准确来说是给父进程返回的,父进程需要获取子进程的退出信息
  3. 返回值是0代表进程代码运行完毕且结果正确
  4. 返回值也可以是其他值,其他的非零返回值代表的是各种不同的错误信息(即代码跑完结果不正确)

我们可以在Linux下简单地验证一下进程退出码:
我们什么代码都不写,直接一运行起来就返回,返回值设置为特殊一点的1124,运行程序查看效果。
在这里插入图片描述

我们运行程序以后进程一下子跑完就退出了,由于当前进程的父进程是bash,所以我们可以用echo指令查看bash内部的函数,输入指令:
echo $?
这条指令可以查看:在bash中,最近一次执行完毕时,对应进程的退出码
所以我们发现第一次查询的退出码,也就是我们自己写程序的退出码是123,第二次查询到的是0,原因是第二次查询到的是echo这一条指令的退出码(指令也是进程)。
在这里插入图片描述

查看进程退出码所代表的含义

我们可以查看一下进程退出码各自所代表的含义:
在C语言中有一个函数叫strerror,可以打印进程退出码的退出信息。我们通过man手册先来查看一下这个函数。
在这里插入图片描述

我们利用strerror函数循环打印0到100的所有退出码各自对应的退出信息:
在这里插入图片描述

程序

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JJP1124

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值