liunx 进程控制

进程创建

再次理解fork

fork创建进程,我们已经了解了。在程序中,如果我们使用fork后,父进程会创建一个子进程,子进程可以通过if(x==0)进行分流,分流结束后,exit(0)退出。子进程也会进行父进程后面的代码。并且发生了神奇的现象,父子进程的同一个变量,有不同的数值。

进程终止

进程终止的三种情况:

  1. 正常退出。结果正确
  2. 正常退出。结果异常
  3. 程序异常终止。

进程退出码

在这里插入图片描述
退出0 则表示退出成功了。当然还有很多退出码,接下来我们用函数一一打印出来
在这里插入图片描述

在这里插入图片描述

实际上,我们平时的指令也是进程。那么他们退出都会有退出码。

在这里插入图片描述
不同情况,会返回不同的错误。

exit函数
使用exit函数退出进程也是我们常用的方法,exit函数可以在代码中的任何地方退出进程,并且exit函数在退出进程前会做一系列工作:

执行用户通过atexit或on_exit定义的清理函数。
关闭所有打开的流,所有的缓存数据均被写入。
调用_exit函数终止进程。
接下来 我们对比 exit 和_exit
在这里插入图片描述
执行程序后:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
我们可以得出结论。

  1. _exit不刷新缓存区,exit刷新缓冲区
  2. _exit更贴近系统低层,exit包装了_exit
    在这里插入图片描述

进程等待

进程等待是父进程为了查看子进程完成情况,以及子进程的退出情况。
进程等待的必要性:

  1. 回收僵尸进程,僵尸进程的危害我们不用多说了 用一个成语形容 ,那就是尸位素餐。
  2. 父进程要知道 我交给子进程办的事是不是办好了。也就是查看他的退出码。
  3. kill 无法杀死僵尸进程

进程状态标识:status
在这里插入图片描述

计算方法:

exitCode = (status >> 8) & 0xFF; //退出码
exitSignal = status & 0x7F;      //退出信号

对于此,系统当中提供了两个宏来获取退出码和退出信号。

  • WIFEXITED(status):用于查看进程是否是正常退出,本质是检查是否收到信号。

  • WEXITSTATUS(status):用于获取进程的退出码。

在这里插入图片描述
我们可以发现被kill杀死的进程退出码则为0。
在这里插入图片描述
尽管我们在进程退出时设置为1.但退出时任然为0.
两种等待方法:wait方法和waitpid方法

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待进程pid,失败返回-1
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进
程的ID。

接下来我们使用这两个函数接口

  1. wait
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
int main()
{
	pid_t id = fork();
	if(id == 0){
		//child
		int count = 10;
		while(count--){
			printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());
			sleep(1);
		}
		exit(1);
	}
	//father
	int status = 0;
	pid_t ret = wait(&status); //等待子进程 并且一直等
cout<<((status >> 8)&0xFF)<<endl;
	if(ret > 0){
		//wait success
		printf("wait child success...\n");
		if(WIFEXITED(status)){
			//exit normal
			printf("exit code:%d\n", WEXITSTATUS(status));
		}
	}
	sleep(3);
	return 0;
}

注意:wait的等待是父进程的等待,并且一直等待直到子进程退出。
在这里插入图片描述

  • waitpid()
    在这里插入图片描述
    如果不带选项,那么和wait一模一样 接下来,我们带入选项。
    WNOHANG: 如果等待集合中的任何子进程都还没有终止,那么就立即返回(返回值为0)。 默认的行为是挂起调用进程,直到有子进程终止 。在等待子进程终止的同时,如果还想做些有用的工作,这个选项会有用。
    WUNTRACED: 挂起调用进程的执行,直到等待集合中的一个进程变成已终止或者被停止 。返回的PID 为导致返回的已终止或被停止子进程的 PID。默认的行为是只返回已终止的子进程。当你想要检査已终止和被停止的子进程时,这个选项会有用。

     可以用或运算把这些选项组合起来 。例如:WNOHANG | WUNTRACED: 立即返回,如果等待集合中的子进程都没有被停止或终止,则返回值为0: 如果有一个停止或终止,则返回值为该子进程的 PID。
    

在这里插入图片描述
没用等待到 waitpid直接返回0。通过 这个方法,我们可以一边等待一边做事情。
在这里插入图片描述
父进程可以边做,边问。

进程替换

替换的基本概念:
用fork创建子进程后,子进程执行的是和父进程相同的程序(但有可能执行不同的代码分支),若想让子进程执行另一个程序,往往需要调用一种exec函数。
注意只是代码区更换,并没有产生新进程。
在这里插入图片描述
如图所示,他们并没有产生新的pcb,只是替换了进程代码和进程数据。

  • 30
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值