简单进程编程说明
简单描述进程编程的几个小知识点
三种特殊的进程
- 僵尸进程
若子进程退出且未告知父进程,称该子进程为 僵尸进程
- 孤儿进程
若父进程退出且子进程尚未退出,该子进程托孤给 init 进程即1号进程,称该子进程为 孤儿进程
- 守护进程
通过结束其父进程,并对其进行一定的处理使其脱离于终端并且在后台运行的子进程,称该子进程为 守护进程
-
原因
一般 僵尸进程 和 孤儿进程 是由于意外情况(如程序员编码时的疏忽等)产生,而 守护进程 是为了执行特定的任务而编写 -
僵尸进程的危害:
子进程退出时,Unix在 释放其大部分资源的同时也会保留一部分信息如进程号等,直到父进程调用
wait
、waitpid
时才释放,因此产生大量的僵尸进程之后将会耗尽有限的进程号而无法产生新进程 -
如何避免产生僵尸进程
- 父进程通过
wait
、waitpid
等函数 signal
函数fork
两次(将其转为孤儿进程)
- 父进程通过
-
如何创建守护进程
- 创建子进程,终止父进程
- 在子进程中创建新会话
- 改变工作目录
- 重设文件创建掩码
- 关闭文件描述符
-
创建守护进程的关键代码(示例)
- fork();
- setsid();
- chdir("/");
- umask(0);
- close(fd);
部分相关函数
fork
vsvfork
函数 | 资源 | 执行顺序 |
---|---|---|
fork | 创建的子进程拷贝父进程的数据段,代码段 | 各自代码段位置往下执行,执行顺序不定 |
vfork | 创建的子进程与父进程共享数据段 | 在子进程没有调用exec和exit之前,父进程阻塞 |
备注:
很多情况下,fork
之后会接着使用exec
,导致很多复制的资源被替换,代价较高,因此有了vfork
如今fork
有了写时复制的机制(cow),所以复制的代价较底(复制父进程页表的代价),而且vfork
伴随着一些安全问题,因此尽量使用fork
exit
vs_exit
函数 | 退出时的步骤 |
---|---|
exit | 1、调用 atexit() 注册的函数;2、关闭打开的流(写所有缓冲输出),删除 TMPFILE 函数建立的临时文件;3、调用 _exit() 函数终止进程 |
_exit | 1、属于该过程的文件描述符都将被关闭;2、进程的任何子进程都由进程1继承;3、进程的父节点发送SIGCHLD信号 |
wait
vswaitpid
函数 | 简易说明 | 参数 | 区别 |
---|---|---|---|
wait | 父进程阻塞等待子进程结束返回信息 | 参数:status得到子进程的退出状态,可为null,即忽略该退出状态 | 一定程度上属于waitpid的特例 |
waitpid | 父进程阻塞等待子进程结束返回信息 | 参数:pid可指定进程号;status与上述相同;option允许改变waitpid的行为 | 不一定阻塞调用者,option使其功能更多样化 |
备注 1:
waitpid
的参数详解:
- pid:
- pid = -1:等待任意一个子进程
- pid > 0 :等待进程号为pid的子进程
- pid = 0 :等待与调用者同进程组的任意一个子进程
- pid < -1:等待组ID等于pid绝对值的任意一个子进程
- option(可组合):
- 0:不使用以下两种参数
- WNOHANG:如果没有已经结束的子进程则马上返回,不予等待
- WUNTRACED:如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会
备注 2:
获取 staus 后检测处理
- WIFEXITED(status) 如果进程子进程正常结束,返回一个非零值
- WEXITSTATUS(status) 如果 WIFEXITED 非零,返回子进程退出码
- WIFSIGNALED(status) 子进程因为捕获信号而终止,返回非零值
- WTERMSIG(status) 如果 WIFSIGNALED 非零,返回信号代码
- WIFSTOPPED(status) 如果进程被暂停,返回一个非零值
- WSTOPSIG(status) 如果 WIFSTOPPED 非零,返回信号代码
system
函数
- 说明:
执行特定命令,阻塞当前进程直到命令执行完毕 - 返回值:
无法启动shell执行命令则返回127
其他错误返回-1
顺利执行返回相关命令的退出码 - 备注:
执行时调用fork
、execve
、waitpid
等函数
进程中止的几种方式
- main函数结束
- 调用
exit
函数 - 调用
_exit
函数 - 调用
abort
函数 - 接收进程终止信号