面试题答案
一键面试1. 数据结构设计
我们可以设计一个结构体来存储每个子进程的相关信息,包括进程ID、创建时间、超时时间等。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
// 定义子进程信息结构体
typedef struct {
pid_t pid;
time_t create_time;
int timeout;
} ChildProcess;
2. 动态超时调整算法
动态超时调整可以根据系统负载来进行。我们可以通过读取/proc/loadavg
文件获取系统负载信息,然后根据负载值调整超时时间。
// 获取系统负载并调整超时时间
int adjust_timeout() {
FILE *loadavg_file = fopen("/proc/loadavg", "r");
if (loadavg_file == NULL) {
perror("fopen");
return -1;
}
double loadavg;
fscanf(loadavg_file, "%lf", &loadavg);
fclose(loadavg_file);
// 假设负载在0 - 10之间,负载越高,超时时间越长
int base_timeout = 5; // 基础超时时间
int new_timeout = base_timeout + (int)(loadavg * 2); // 简单的调整算法
return new_timeout;
}
3. 信号处理机制
为了避免僵尸进程,我们需要处理SIGCHLD
信号。在信号处理函数中,我们可以使用waitpid
来回收子进程资源。
// SIGCHLD信号处理函数
void sigchld_handler(int signum) {
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// 处理子进程退出
printf("Child process %d terminated\n", pid);
}
}
4. 关键C语言代码实现
以下是完整的代码示例,展示如何创建子进程、设置动态超时并处理信号。
int main() {
// 注册SIGCHLD信号处理函数
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;
}
ChildProcess *child_processes[100];
int child_count = 0;
for (int i = 0; i < 10; i++) {
// 创建子进程
pid_t pid = fork();
if (pid == 0) {
// 子进程
printf("Child process %d started\n", getpid());
sleep(2); // 模拟子进程工作
exit(0);
} else if (pid > 0) {
// 父进程
ChildProcess *new_process = (ChildProcess *)malloc(sizeof(ChildProcess));
new_process->pid = pid;
new_process->create_time = time(NULL);
new_process->timeout = adjust_timeout();
child_processes[child_count++] = new_process;
} else {
perror("fork");
return 1;
}
}
// 等待子进程或超时
for (int i = 0; i < child_count; i++) {
int status;
time_t current_time = time(NULL);
while (difftime(current_time, child_processes[i]->create_time) < child_processes[i]->timeout) {
pid_t result = waitpid(child_processes[i]->pid, &status, WNOHANG);
if (result == child_processes[i]->pid) {
printf("Child process %d exited normally\n", child_processes[i]->pid);
break;
}
sleep(1);
current_time = time(NULL);
}
if (difftime(current_time, child_processes[i]->create_time) >= child_processes[i]->timeout) {
printf("Child process %d timed out\n", child_processes[i]->pid);
kill(child_processes[i]->pid, SIGKILL); // 超时则杀死子进程
}
free(child_processes[i]);
}
return 0;
}
上述代码实现了以下功能:
- 数据结构设计:定义了
ChildProcess
结构体来存储子进程相关信息。 - 动态超时调整算法:通过读取
/proc/loadavg
文件获取系统负载,并据此调整每个子进程的等待超时时间。 - 信号处理机制:注册了
SIGCHLD
信号处理函数,在子进程结束时及时回收资源,避免产生僵尸进程。 - 关键代码实现:展示了如何在高并发场景下创建子进程、设置动态超时并处理子进程的等待和超时情况。