MST

星途 面试题库

面试题:C语言在复杂场景下等待指定子进程的优化

假设有多个子进程同时运行,每个子进程执行不同的任务且执行时间不确定。现在父进程需要等待其中特定的一个子进程完成,同时要避免父进程长时间阻塞影响其他操作(例如定期检查其他子进程状态等)。使用C语言在Linux环境下实现该功能,说明你采用的同步机制和如何确保程序的高效性与稳定性,并给出代码框架和关键代码段。
48.2万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

采用的同步机制

使用waitpid函数结合WNOHANG选项来实现非阻塞等待特定子进程。waitpid函数可以指定等待特定的子进程,WNOHANG选项使得父进程在指定子进程未结束时不会阻塞,而是立即返回,这样父进程就可以去执行其他操作,如定期检查其他子进程状态。

确保程序高效性与稳定性的方法

  1. 高效性
    • 使用非阻塞等待方式,避免父进程长时间阻塞,父进程可以在等待特定子进程的同时执行其他任务,提高CPU利用率。
    • 合理安排子进程任务,避免不必要的资源竞争和重复计算。
  2. 稳定性
    • 检查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;
}

在上述代码中:

  1. 创建多个子进程:通过fork函数创建了三个子进程,每个子进程执行不同的任务(这里简单用sleep模拟)。
  2. 信号处理:注册了SIGCHLD信号处理函数sigchld_handler,用于处理子进程结束信号,避免出现僵尸进程。
  3. 非阻塞等待:在父进程的主循环中,使用waitpid函数结合WNOHANG选项非阻塞等待特定子进程(这里是child_pid3)。根据waitpid的返回值进行不同处理,未结束时父进程执行其他操作,结束时进行相应的状态处理。