进程控制

目录

进程创建

fork函数

写时拷贝

进程终止

进程退出场景

进程常见退出方法

进程等待

进程等待的必要性

进程等待的方法

wait方法

waitpid方法

获取子进程status

等待行为options

进程替换

各类程序替换函数的使用

命名理解

execl函数

execv函数

execlp函数

execvp函数

execle函数

execve函数


进程创建

fork函数

在linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

返回值:创建失败返回-1;创建成功给父进程返回子进程的id,给子进程返回0

fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。

写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。

进程控制_第1张图片

进程终止

进程退出场景

main函数的return值是进程的退出码。0:success    !0:failed

代码运行完毕,结果正确

代码运行完毕,结果不正确

代码异常终止(程序崩溃,退出码也变得没有了意义)

打印退出码如下:

 进程控制_第2张图片

 进程控制_第3张图片

我们可以看见,不同的退出码对应不同的信息。

异常退出: ctrl + c,信号终止

进程常见退出方法

正常终止(可以通过 echo $? 查看进程退出码):

1. 从main函数return,代表进程退出 

2. 任何地方调用exit,都代表终止进程,参数是退出码

3. _exit终止进程,但是不会进行进程的后续收尾工作,比如刷新缓冲区。 

进程控制_第4张图片

这里我们打印“hello World!”这个字符串,没有带换行,也就是这个字符串 暂时被保存在缓冲区里边的。这里使用_exit(退出码)是不会由任何结果的,因为它直接退出程序,不会为进程处理任何后续工作。使用exit(退出码)却能打印出来,因为他会为进程处理后续的工作,比如刷新缓冲区。

进程控制_第5张图片

进程等待

进程等待的必要性

1、子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。

2、进程一旦变成僵尸状态,那就刀枪不入,kill -9 也无能为力,因为谁也没有办法 杀死一个已经死去的进程。

3、父进程派给子进程的任务完成的如何,我们需要知道。比如,子进程运行完成,结果对还是不对, 或者是否正常退出。

4、父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息 

5、可以保证时序问题,子进程先退出,父进程后退出

进程等待的方法

wait方法

查看文档

进程控制_第6张图片

返回值: 成功返回被等待进程pid,失败返回-1。

参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

执行下边代码

进程控制_第7张图片

下边是监控打印结果:进程控制_第8张图片

 这里演示了父进程等待回收子进程的全过程。

waitpid方法

返回值:

        当正常返回的时候waitpid返回收集到的子进程的进程ID;

        如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

        如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

参数:

         pid:

                Pid=-1,等待任意一个子进程。与wait等效。

                Pid>0.等待指定进程。

        status:

                WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)

                WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

        options: WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

复用刚刚的代码依旧可以完成子进程回收。

进程控制_第9张图片

获取子进程status

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。

如果传递NULL,表示不关心子进程的退出状态信息

否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。

status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特 位):

进程控制_第10张图片

等待行为options

0:默认行为,阻塞等待。WNOHANG:非阻塞等待

非阻塞等待:可能需要多次检测。

进程控制_第11张图片

进程替换

进程不变,仅仅替换当前进程的代码和数据的技术叫做进程的程序替换

程序替换的本质就是把指定的进程+数据,加载进特定进程的上下文中

进程控制_第12张图片

 但是,我们知道父子进程的代码是共享的。这里解释一下:父子进程代码共享的前提是代码没有发生改变。如果发生了改变,是会发生写时拷贝的。

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。

如果调用出错则返回-1

所以exec函数只有出错的返回值没有成功的返回值

比如下类代码

进程控制_第13张图片

 进程控制_第14张图片

各类程序替换函数的使用

其实有六种以exec开头的函数,统称exec函数:

进程控制_第15张图片

命名理解

        · l(list) : 表示参数采用列表

        · v(vector) : 参数用数组

        · p(path) : 有p自动搜索环境变量PATH

        · e(env) : 表示自己维护环境变量

execl函数

进程控制_第16张图片

进程控制_第17张图片

 执行结果如下

进程控制_第18张图片

execv函数

execv函数和execl函数其实没有什么区别。就是传递参数的方式不一样。execl函数使用可变参数列表传参,execv函数使用指针数组传参

进程控制_第19张图片

 执行代码如下:

进程控制_第20张图片

执行结果

 进程控制_第21张图片

execlp函数

进程控制_第22张图片

执行代码:

 进程控制_第23张图片

execvp函数

进程控制_第24张图片

执行代码:

 进程控制_第25张图片

execle函数

进程控制_第26张图片

 执行代码

进程控制_第27张图片

execve函数

进程控制_第28张图片

执行代码:

 进程控制_第29张图片

进程控制_第30张图片

你可能感兴趣的:(Linux,linux)