面试题答案
一键面试采用的同步机制
使用waitpid
函数结合WNOHANG
选项来实现非阻塞等待特定子进程。waitpid
函数可以指定等待特定的子进程,WNOHANG
选项使得父进程在指定子进程未结束时不会阻塞,而是立即返回,这样父进程就可以去执行其他操作,如定期检查其他子进程状态。
确保程序高效性与稳定性的方法
- 高效性:
- 使用非阻塞等待方式,避免父进程长时间阻塞,父进程可以在等待特定子进程的同时执行其他任务,提高CPU利用率。
- 合理安排子进程任务,避免不必要的资源竞争和重复计算。
- 稳定性:
- 检查
waitpid
等系统调用的返回值,及时处理错误情况,如子进程异常终止等。 - 对子进程和父进程进行适当的信号处理,例如处理
SIGCHLD
信号,确保在子进程结束时能正确通知父进程。
- 检查
代码框架和关键代码段
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
// 信号处理函数
void sigchld_handler(int signum) {
// 处理子进程结束信号,这里可以进行资源清理等操作
// 例如调用waitpid处理僵尸进程
while (waitpid(-1, NULL, WNOHANG) > 0);
}
int main() {
pid_t child_pid1, child_pid2, child_pid3;
// 创建子进程1
child_pid1 = fork();
if (child_pid1 == 0) {
// 子进程1执行的任务
printf("Child 1 is running...\n");
sleep(5);
printf("Child 1 is done.\n");
exit(0);
}
// 创建子进程2
child_pid2 = fork();
if (child_pid2 == 0) {
// 子进程2执行的任务
printf("Child 2 is running...\n");
sleep(3);
printf("Child 2 is done.\n");
exit(0);
}
// 创建子进程3,假设我们要等待这个子进程
child_pid3 = fork();
if (child_pid3 == 0) {
// 子进程3执行的任务
printf("Child 3 is running...\n");
sleep(4);
printf("Child 3 is done.\n");
exit(0);
}
// 注册信号处理函数
struct sigaction sa;
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
// 父进程主循环
while (1) {
// 非阻塞等待特定子进程(这里假设是child_pid3)
int status;
pid_t result = waitpid(child_pid3, &status, WNOHANG);
if (result == child_pid3) {
if (WIFEXITED(status)) {
printf("Child 3 exited with status %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Child 3 was terminated by signal %d\n", WTERMSIG(status));
}
break;
} else if (result == 0) {
// 子进程未结束,父进程执行其他操作
printf("Parent is doing other things...\n");
// 例如检查其他子进程状态
sleep(1);
} else if (result == -1) {
perror("waitpid");
break;
}
}
return 0;
}
在上述代码中:
- 创建多个子进程:通过
fork
函数创建了三个子进程,每个子进程执行不同的任务(这里简单用sleep
模拟)。 - 信号处理:注册了
SIGCHLD
信号处理函数sigchld_handler
,用于处理子进程结束信号,避免出现僵尸进程。 - 非阻塞等待:在父进程的主循环中,使用
waitpid
函数结合WNOHANG
选项非阻塞等待特定子进程(这里是child_pid3
)。根据waitpid
的返回值进行不同处理,未结束时父进程执行其他操作,结束时进行相应的状态处理。