面试题----僵尸进程的四种处理方法

本文介绍了父进程如何通过wait、waitpid及signal函数管理子进程的方法,包括等待子进程结束、忽略子进程结束信号以及通过fork两次实现子进程由init接管等技巧。

l  父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起

l  如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收

l  如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号

l  还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。

 

转载于:https://www.cnblogs.com/qingergege/p/7832853.html

### 进程关系相关的面试题及解答 #### 1. **进程与线程的区别是什么?** 进程是操作系统分配资源的基本单位,而线程是CPU调度和执行的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源,例如内存空间和文件描述符。由于线程之间的切换开销较小,多线程程序通常比多进程程序更高效[^1]。 #### 2. **什么是父子进程?它们之间如何通信?** 当一个进程创建另一个进程时,创建者称为父进程,被创建的进程称为子进程。父子进程之间的通信可以通过多种方式实现,包括管道(Pipe)、信号量(Semaphore)、共享内存(Shared Memory)以及消息队列(Message Queue)等。其中,管道是最简单的进程间通信(IPC)机制之一,允许父进程和子进程之间进行单向或双向数据传输[^1]。 #### 3. **如何在Linux系统中创建一个新的进程?** 在Linux系统中,`fork()` 系统调用用于创建一个新的进程。新进程是调用进程(父进程)的副本,它几乎完全复制了父进程的状态,包括代码、数据段和堆栈。`fork()` 返回值在父进程中为子进程的PID,在子进程中为0,通过此返回值可以区分父子进程并分别执行不同的逻辑[^1]。 ```c #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { pid_t pid = fork(); if (pid == 0) { printf("这是子进程,PID: %d\n", getpid()); } else if (pid > 0) { printf("这是父进程,PID: %d, 子进程PID: %d\n", getpid(), pid); } else { printf("进程创建失败。\n"); } return 0; } ``` #### 4. **孤儿进程和僵尸进程的区别是什么?** 孤儿进程是指其父进程已经终止但该进程仍在运行的进程。在这种情况下,系统会将孤儿进程重新分配给 `init` 进程(PID为1),由 `init` 进程负责回收孤儿进程的资源。 僵尸进程是指进程已经终止,但其父进程尚未通过 `wait()` 或 `waitpid()` 获取其退出状态。此时,进程的条目仍然保留在进程表中,占用系统资源。如果父进程不调用 `wait()` 或 `waitpid()`,僵尸进程将持续存在,可能导致资源泄漏[^1]。 #### 5. **如何避免僵尸进程的产生?** 为了避免僵尸进程的产生,父进程应该在其子进程结束时调用 `wait()` 或 `waitpid()` 函数来获取子进程的退出状态。此外,可以在父进程中设置信号处理函数,捕获 `SIGCHLD` 信号,并在信号处理函数中调用 `wait()` 或 `waitpid()` 来回收子进程资源。 ```c #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> void sigchld_handler(int signum) { while (waitpid(-1, NULL, WNOHANG) > 0); // 回收所有已终止的子进程 } int main() { signal(SIGCHLD, sigchld_handler); // 注册信号处理函数 pid_t pid = fork(); if (pid == 0) { printf("子进程正在运行...\n"); sleep(2); printf("子进程即将退出。\n"); exit(0); } printf("父进程正在运行...\n"); sleep(5); printf("父进程即将退出。\n"); return 0; } ``` #### 6. **进程间的同步机制有哪些?** 进程间的同步机制主要包括以下几种: - **信号量(Semaphore)**:用于控制对共享资源的访问,确保多个进程不会同时修改共享资源。 - **互斥锁(Mutex)**:类似于二进制信号量,用于保护临界区资源,防止并发访问导致的数据不一致问题。 - **条件变量(Condition Variable)**:通常与互斥锁配合使用,用于等待某个条件成立后再继续执行。 - **读写锁(Read-Write Lock)**:允许多个读操作同时进行,但写操作必须独占资源。 - **屏障(Barrier)**:用于多个进程到达某个点后一起继续执行,常用于并行计算场景[^1]。 #### 7. **进程调度算法有哪些?简要说明其原理。** 常见的进程调度算法包括: - **先来先服务(FCFS)**:按照进程到达的顺序依次调度,简单但可能导致长作业等待时间过长。 - **短作业优先(SJF)**:优先调度预计运行时间最短的进程,减少平均等待时间,但需要预测进程的运行时间。 - **优先级调度(Priority Scheduling)**:根据进程的优先级进行调度,高优先级进程优先执行,可能造成低优先级进程饥饿。 - **轮转调度(Round Robin)**:每个进程按固定时间片轮流执行,适用于实时系统,保证公平性。 - **多级反馈队列调度(Multilevel Feedback Queue Scheduling)**:结合了多种调度策略,动态调整进程的优先级和时间片,适应不同类型的进程需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值