Linux进程控制--进程的创建与终止
Posted 蓝乐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程控制--进程的创建与终止相关的知识,希望对你有一定的参考价值。
进程的创建与终止
进程控制包括进程的创建、终止、等待与替换。本文将介绍进程的创建与终止。
进程的创建
进程的创建包括两个方面:一种是使用命令行的启动命令来创建进程;另一个是在程序本身通过fork函数来创建子进程
fork函数
fork函数我们并不陌生,调用fork接口将会以父进程为模板来创建子进程,其中子进程的大多数据都是从父进程继承而来的。
fork函数的返回值
我们之前说fork函数有两个返回值,其实这是不准确的,如何理解呢?
#include <stdio.h>
#include <sys/types.h>
int main()
pid_t id = fork();
if(id == 0)//子进程
while(1)
printf("I am a child,pid:%d,ppid:%d,id:%d\\n",getpid(),getppid(),id);
sleep(1);
else if(id > 0)//父进程
while(1)
printf("I am the father,pid:%d,ppid:%d,id:%d\\n",getpid(),getppid(),id);
sleep(1);
else
//error
return 0;
我们之前说,fork函数创建完子进程后,父子进程代码共享,数据各自私有一份。其实,在子进程刚创建时,父子进程的代码和数据都是共享的(此时代码段和数据段的权限都是只读的);而当子进程和父进程要修改数据时,操作系统(OS)就会进行写时拷贝,此时操作系统修改权限,将父进程的数据段拷贝一份到物理内存的另一块地方,这便是子进程的数据段。
这边能解释fork函数调用后,子进程就已经存在了,此时父子进程代码共享,只不过对于父进程而言,fork函数的返回值大于0,而子进程的返回等于0,从而让父子进程进入不同的业务逻辑。
写时拷贝
上面我们提到了创建父进程时会进行写时拷贝,即子进程在不写入数据之前和父进程共享代码段及数据段,而当子进程要写入时操作系统则另开一块空间给子进程,并将父进程的数据段拷贝到这块空间供子进程写入。
写时拷贝的意义
那么为什么要有写时拷贝呢?我们直接在创建子进程的同时给子进程开辟一块空间让子进程左右数据段不就好了,何必进行写时拷贝这么麻烦呢?
其实,首先,并非所有的数据父子进程都会进行写入,因为有很多数据都不需要写入修改,此时将这些数据都拷贝一份会造成内存和系统资源的浪费。
其次,调用fork函数时,除去创建数据结构,如果再加上拷贝数据的话,会导致fork函数调用的效率降低。
再者,fork函数本身就是向系统需要资源,而需求更少的资源要比需求更多的资源更容易调用成功。
fork函数调用失败的情况
1.系统中有太多的进程,资源不足
2.实际用户的进程数超过了限制
进程的终止
退出码
在介绍进程的终止之前,我们首先来了解一下退出码的概念。
我们在写main函数时,会有个返回值,这个返回值就是退出码,其代表进程退出,并返回结果是否运行正确,而我们经常返回的0则表示进程成功运行。main函数的退出码是给系统看的,那如果我们用户想查看进程的退出码,就需要使用下面这条指令:
echo $?
我们可以通过strerror函数接口来查看系统中常见的错误码意义:
当然,我们也可以自定义错误码的含义,依照个人习惯即可。
退出码的意义
进程退出有三种情况:
- 代码正常运行,且结果正确,返回0
- 代码正常运行,但结果错误,返回非0
- 代码没有运行完,程序崩溃了,此时退出码没有意义
那么,对于父进程而言,掌握了子进程的退出码,就可以掌握子进程的退出情况,这对于父进程而言是必要的。
了解完退出码后,我们就可以来认识进程的终止了。
进程常见的退出方法
正常终止方法
- main函数返回
- exit函数调用
- _exit函数调用
异常终止方法
ctrl + c
是信号终止
exit函数&_exit函数
我们先来看两段代码:
int main()
printf("hello world");
exit(1);
int main()
printf("hello world");
_exit(1);
由此可见,调用exit函数,在退出时会进行后续资源的处理,包括刷新缓冲区;而_exit函数,并不会进行后续资源的处理,而是直接终止程序。
深入理解进程终止
从操作系统的层面上看进程终止的核心就是归还资源。
而归还资源,对于数据结构对象而言,则是“释放”曾经为管理进程所维护的一切数据结构对象,这里的“释放”并不是将数据结构对象销毁,而是将其设置为不使用的状态,并保持起来;而如果这种不使用的对象多了,就有一个“数据结构池”。同样的,内存池也是近似如此。
进程终止时,操作系统将其归为闲置状态,并取消其曾经的链接关系。
而对于程序代码和数据所占用的内存空间,和数据结构对象一样,并非将代码和数据清空,而是内存设置为无效状态。
以上是关于Linux进程控制--进程的创建与终止的主要内容,如果未能解决你的问题,请参考以下文章