Linux的进程控制(创建和终止)

本文详细解析了C语言中fork函数的工作原理,包括子进程的创建、写实拷贝机制,以及进程终止时的退出码和异常处理。还介绍了exit和_exit的区别,帮助读者掌握进程管理的基础知识。
摘要由CSDN通过智能技术生成

进程创建

fork

我们前面已经认识过fork函数, 用fork创建新进程后, 新建立的进程为子进程, 该进程为父进程。fork给父进程返回的是子进程的pid, 给子进程返回的是0, 出错时返回-1

进程调用fork后, 当控制转移到内核中的fork代码后, 内核做:

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

用fork创建子进程后如何发生写实拷贝的?

当我们在创建出子进程后, 父进程的页表中原本对应的数据区, 将会由可读可写变化为只可读(当然子进程的权限也是只可读)所以当进程需要对数据进行修改时, 就会触发操作系统的权限问题, 但是在审核的时候, 系统会发现你这个区域本来是可写的, 只是暂时变为了只可读, 所以针对这种情况, 操作系统不会当做异常处理, 而是变成操作系统把数据给你拷贝一份, 谁写的就把谁的页表映射改到新开辟的空间, 并且把权限改回可读可写然后我们就可以正常访问了

为什么要用写实拷贝的方式维护父子进程的数据区

因为我们的子进程可能只会修改父进程的一部分数据,一味的拷贝会造成内存资源的浪费也会导致效率的降低(要多拷贝一些内容)

fork的常规用法

1一个父进程希望复制自己, 使父子进程同时执行不同的代码, 例如父1进程等待客户端请求, 生成子进程来处理请求

2一个进程要处理一个不同的程序, 例如子进程从fork返回后, 调用exec函数

用fork创建多个子进程

在这里插入图片描述
子进程执行完run后就直接结束掉, 而父进程继续循环创建子进程

这多个进程谁先被执行?

这完全取决于调度器先调度谁, 父子进程以及兄弟进程谁先执行我们不可知

进程终止

为什么main函数要返回值, 这个值返回给谁了?为什么要返回这个值?

在这里插入图片描述

我们return的其实就是进程的退出码, 表征进程的退出状态。
在这里插入图片描述

0 --> success

这个退出码会被该进程的父进程拿到,(在这里就是被bash拿到)

这个退出码会被保存在?这个变量里
我们可以使用echo $?查看上一个进程的退出码
在这里插入图片描述

在进程中, 谁会关心我的进程结束状态呢?

一般而言, 是我们进程的父进程会关心

main函数的返回值本质表示:
进程完成时是否是正确的结果,如果不是可以用不同的数字,表示不同的出错原因!

strerror查看错误码信息

c语言自带的库函数strerror能将对应的错误码转化为错误信息

在这里插入图片描述
在这里插入图片描述
我们验证一下
在这里插入图片描述
我们先是用ls指令查看一个不存在的文件, 然后报错没有该文件, 我们查表发现该错误对应的错误码为2
在这里插入图片描述
查看上一个进程的退出码,发现确实是2
在这里插入图片描述

errno是c语言提供的一个全局变量, 我们调用c语言内部的库函数, 如果调用失败了, c语言会将这个默认的全局变量errno设置成对应的数字表明为什么调用出错
在这里插入图片描述在这里插入图片描述

上诉出现的错误代码都是跑完了的, 但是进程的退出还有一种情况, 那就是异常退出
对于异常退出的进程, 他的退出码还有意义吗?
因为我们不清楚异常退出的进程他是否进行了正常的return, 所以一般是不用他的退出码。

所以我们在关心进程退出的时候, 应该先关心进程是否异常, 再关心进程的退出码

我们知道了异常退出的进程, 他的退出码没有意义, 但是, 我们该如何知道进程是否是异常退出的呢?

进程异常

进程出现异常, 本质上是我们的进程收到的了对应的信号!!

信号

在这里插入图片描述

在这里插入图片描述
可以看到我们的进程在正常的跑, 并没有任何的错误

在这里插入图片描述
但是当我们在给他发送8号信号的时候, 他就发生段错误了。

所以我们父进程想要判断子进程是否是异常退出, 只需要看是否收到了对应的信号, 如果没收到, 那么自然子进程就是正常退出的, 我们此时就可以去查看子进程的退出码了

exit 与 _exit

他们两个都可以直接终止进程,并且返回对应的退出码

他们的区别是

在这里插入图片描述
如果我们是有exit()退出进程时, 这段信息是先等一会, 然后再被打印出来
(这个原因我们讲过, 是因为信息是先被保存到了缓存区, 等刷新后才会显示出来)

而如果我们使用_exit()退出进程, 会发现直接没有打印消息了所以_exit()在退出进程的时候, 是不会将缓存区里的信息刷新出来的。


_exit()是系统的调用接口, 我们用户在调用这个接口后, 就会直接将当前进程终止。

而如果我们调用的是exit()函数, 他会先把我们之前打开的各种文件啊, 流啊什么的都刷新, 然后再去调用_exit()。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值