前言:
在操作系统中,进程是资源分配的基本单位。进程之间存在着复杂的关系,其中最重要的就是父子进程关系和僵尸进程。
1.父子进程:
父子进程是操作系统中最基本的进程关系。当一个进程创建另一个进程时,被创建的进程就成为父进程的子进程。子进程继承了父进程的大部分属性,如环境变量、工作目录等。可以初略的认为子进程只是父进程的拷贝。
下面我用两个简单的示例,来演示了父子进程。在这个示例中,ParentChildProcess
类创建了一个子进程ChildProcess
,并等待子进程结束。子进程在执行5秒钟的任务后退出。
(java)
public class ParentChildProcess {
public static void main(String[] args) {
System.out.println("Parent process started, PID: " + ProcessHandle.current().pid());
ProcessBuilder processBuilder = new ProcessBuilder("java", "ChildProcess");
try {
Process childProcess = processBuilder.start();
int childPid = (int) childProcess.pid();
System.out.println("Child process started, PID: " + childPid);
int exitCode = childProcess.waitFor();
System.out.println("Child process exited with code: " + exitCode);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Parent process finished.");
}
}
class ChildProcess {
public static void main(String[] args) {
System.out.println("Child process started, PID: " + ProcessHandle.current().pid());
// 模拟子进程执行一些任务
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Child process finished.");
}
}
(c):
- 父进程首先打印自己的进程ID。
- 使用
fork()
函数创建子进程。 - 如果返回值是-1,表示创建子进程失败,打印错误信息并退出。
- 如果返回值是0,表示当前进程是子进程,打印子进程的进程ID,然后模拟执行5秒钟的任务,最后退出。
- 如果返回值大于0,表示当前进程是父进程,打印等待子进程完成的信息。
- 父进程使用
waitpid()
函数等待子进程退出,并获取子进程的退出状态。 - 根据退出状态,打印子进程是否正常退出。
- 最后,父进程打印自己已经完成。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t pid;
printf("Parent process started, PID: %d\n", getpid());
// 创建子进程
pid = fork();
if (pid == -1) {
// 创建子进程失败
perror("fork");
return 1;
} else if (pid == 0) {
// 子进程
printf("Child process started, PID: %d\n", getpid());
// 模拟子进程执行一些任务
sleep(5);
printf("Child process finished.\n");
return 0;
} else {
// 父进程
int status;
printf("Parent process waiting for child process to finish...\n");
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Child process exited with status %d\n", WEXITSTATUS(status));
} else {
printf("Child process did not exit normally\n");
}
printf("Parent process finished.\n");
return 0;
}
}
编译代码以后,会得到以下效果
2.僵尸进程产生的原因:
当一个子进程退出时,它的父进程应该及时回收子进程的资源,如内存、CPU时间等。但是,如果父进程没有及时回收子进程的资源,则子进程会变成"僵尸进程"。
注意:僵尸进程不会占用系统资源,但它会一直存在于进程表中,直到父进程对其进行回收。
接下里我们就直接用shell创建一个子进程然后没有父进程来对他进行回收。看一下具体的效果。在这个示例中,首先我们使用父进程创建了一个子进程,然后等待5秒钟后退出父进程。但是,子进程在父进程退出之前并没有完全执行完毕,所以现在子进程就没有对应的父进程来回收了。也就成为了僵尸进程。注意这里的僵尸进程和死循环的区别哦。
#!/bin/bash
echo "Parent process started, PID: $$"
# 创建子进程
./child_process.sh &
child_pid=$!
echo "Child process started, PID: $child_pid"
# 等待5秒钟
sleep 5
echo "Parent process finished."
#!/bin/bash
echo "Child process started, PID: $$"
# 模拟子进程执行一些任务,然后直接退出
sleep 10
exit 0
3.避免产生僵尸进程方法:
父进程需要及时回收子进程的资源。在Java中,可以使用Process.waitFor()
方法等待子进程退出,并获取退出状态码。在Shell脚本中,可以使用wait
命令等待子进程退出。
4.总结:
父子进程是操作系统中实现多任务并发处理的基础,而僵尸进程则是这一机制的潜在副作用。减少僵尸进程的发生,保障系统稳定高效运行。
扫描二维码关注公众号,回复:
17497971 查看本文章
