目录
进程的创建和终止
进程创建时,操作系统先为进程创建内核数据结构task_struct、mm_struct、页表等,然后再从磁盘中将进程的代码和数据加载进内存中
进程终止时,先释放曾经的代码和数据所占据的空间,后释放内核数据结构,并将进程修改为僵尸状态Z
进程终止的三种情况
main函数的return
基本概念:main函数有返回值,是因为父进程想要知道子进程运行的结果,为0表示成功,不为0表示各种原因的失败
默认退出码
基本概念:sterror函数可以打印每个数字对应的错误信息(系统默认提供的)
perror、sterror、errno的区别
自定义退出码
基本概念:使用枚举类型可以自定义退出码,将一个完全大写的变量与某个数字进行绑定
补充内容:代码执行时,出现异常导致提前退出的根本原因是因为该进程收到了OS发给它的信号,可以使用kill - l指令查看所有信号及其编号,并找到相应的信号名称,从而确定进程的退出原因
注意事项:退出码和退出信号互斥,一个进程的退出信息中只可能有其中一个!!!
exit函数
函数原型:void exit(int status);
- status:进程的终止原因,父进程通过wait获取,为0表示进程正常退出,为1表示异常退出
包含头文件:<stdlib.h>
功能:遇到exit进程直接终止,并将退出码存放在status中
int test3()
{
int sum = 0;
for(int i = 0; i < 50; ++i)
{
sum += i;
}
exit(99);
return sum;
}
int main()
{
int ret = test3();
exit(ret);
return 0;
}
[yyf@hecs-165234 linux101]$ ./myproc
[yyf@hecs-165234 linux101]$ echo $?
99
_exit函数
函数原型:void _exit(int status);
包含头文件:<unistd.h>
功能:立即终止当前进程,而不进行常规的清理工作(如刷新文件缓冲区、关闭文件流等)
注意事项:_exit和_Exit函数本质上是同一个函数
NAME
_exit, _Exit - terminate the calling process
SYNOPSIS
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
exit和_exit的区别
进程等待
基本概念:进程退出时,必须要将退出信息交给它的父进程,正常情况下父进程也会一直等待接收子进程的退出信息,通过接收子进程的退出信息,可以获取子进程的退出原因并作出相应处理,如果父进程不接收子进程的退出信息(此时子进程的状态为Z),也直接退出,则子进程一直处于僵尸状态,处于僵尸状态的子进程过多会导致系统无法创建新的进程
wait函数
基本概念:wait()
函数是 Unix/Linux 系统中用于等待子进程结束的系统调用。父进程调用 wait()
后,会阻塞,直到它的某个子进程终止,wait()
随后会回收该子进程的系统资源(如进程表项),并返回终止的子进程的退出状态。使用 wait()
可以防止产生僵尸进程,确保父进程获取到子进程的退出状态并清理其资源
函数原型:pid_t wait(int *status);
- status:输出型参数,由OS填充,用于存储子进程的退出信息(退出码或者退出信号),通过宏函数(如
WIFEXITED
、WEXITSTATUS
)可以分析退出状态,判断子进程是正常退出还是被信号终止
pid_t child_pid = wait(&status); // 等待子进程结束
if (WIFEXITED(status))
{
printf("父进程:子进程 %d 正常退出,退出码:%d\n", child_pid, WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("父进程:子进程 %d 因信号终止,信号编号:%d\n", child_pid, WTERMSIG(status));
}
- 若不关心子进程的退出原因,可以将status设为NULL
返回值:等待成功时返回子进程的pid,等待失败时返回-1
等待失败的原因:
wait()
正在阻塞等待子进程结束,此时进程接收到一个信号(如Ctrl+C
产生的SIGINT
),导致wait()
调用中断- 没有子进程可等待
- 等待的进程的父进程提前退出,该进程变为孤儿进程
包含头文件:<sys/types.h> 和 <sys/wait.h>
注意事项:父进程一旦调用wait,就会被阻塞,只要有一个子进程结束,就会去接收该子进程的退出信息并将状态转为就绪态
关于status指针和子进程退出信息存在形式的解释
基本概念:wait函数和waitpid函数中的整形指针status指向的存放子进程退出信息的一个整形变量,但是该变量的钱两个字节不会被使用(官方规定)在后两个字节中,前八位表示退出码,后七位表示退出信号,中间一位用于标识coredump(后续会解释)
打印退出信息、退出码和退出信号:
- 进程未受到信号干扰,顺利执行完时的退出码不为0,退出信号为0
打印因信号终止时的退出码和退出信号:
- 因信号导致进程终止时,退出码为0,退出信号不为0
waitpid函数
基本概念:是 wait()
函数的一个更强大的变种,它允许父进程精确控制等待的子进程,并且可以选择阻塞或非阻塞的方式等待子进程终止
包含头文件:<sys/types.h> 和 <sys/wait.h>
函数原型:pid_t waitpid(pid_t pid,int *status,int options);
pid:为-1则表示等待任意一个子进程,不为-1则表示等待一个指定子进程
status:输出型参数,用于存放子进程的退出信息
options:控制
waitpid()
的行为
0
:默认行为,阻塞等待直到指定子进程退出。WNOHANG
:非阻塞模式,如果没有子进程退出,立即返回,父进程继续执行自己的内容WUNTRACED
:如果子进程已停止但尚未终止,也立即返回其状态
返回值:
- 如果成功等到了一个子进程结束,则返回该子进程PID
- 如果在options中指定了WNOHANG选项,且没有任何一个子进程已经终止,则返回0
-
如果出错(例如,指定了无效的 PID 或者调用过程被信号中断),则返回 -1
阻塞等待与非阻塞等待
阻塞等待:父进程在等待子进程返回时什么都不做(稳定可靠)
非阻塞等待:父进程在等待子进程返回时可以去做一些事情(while循环实现),并且在做事情的间隙频繁访问子进程是否返回
非阻塞轮询 = 非阻塞等待 + 循环
父进程会利用回调函数在阻塞轮询的时候执行自己的事情
~over~