You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++实现定期中断子进程,超时终止父子进程的问题求助

问题描述

程序A通过fork()执行程序B,要求每5秒中断程序B对应的进程;若用户在规定时间内按下任意键,则恢复进程运行,之后再次按相同时间间隔中断;若未按键,则提前终止程序A和程序B。以下是我尝试的代码,但无法正常运行,作为C++新手,希望得到建议或解决方案。

#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

using namespace std;
using namespace chrono;

int pid;

void signal_handler(int signum) {
    cout << "Programm B is interrupted. Please enter any key within 5 or the programm will be terminated" << endl;
    kill(pid,SIGSTOP);
    alarm(5);
    pause();
    alarm(5);

}
int main(int argc, char* argv[]) {

  //Usage
  if(string(argv[1]) == "h" || string(argv[1]) == "help"){
    cout << "usage" << endl;
    return 0;
  }

  signal(SIGALRM, signal_handler);
  pid = fork();

  if (pid == 0) {

    cout << "Name of programm B: " << argv[1] << endl;
    cout << "PID of programm B: " << getpid() << endl;
    execvp(argv[1], &argv[1]);

  } else if (pid > 0) {

    cout << "PID of programm A: " << getpid() << endl;

    high_resolution_clock::time_point t1 = high_resolution_clock::now();
    waitpid(pid, nullptr, 0);
    high_resolution_clock::time_point t2 = high_resolution_clock::now();

  
    auto duration = duration_cast<milliseconds>(t2 - t1).count();
    cout << "Computing time: " << duration << "ms" << endl;
  } else {

    cerr << "error << endl;
    return 1;

}
  return 0;
}
问题分析与修复方案

原代码核心问题

  • 未启动初始闹钟:主进程没有设置第一个alarm(5),导致不会触发第一次中断。
  • pause()逻辑缺陷:pause()会等待任意信号,无法精准捕获用户按键,且没有处理输入缓冲问题。
  • 信号处理逻辑错误:中断进程后没有恢复操作(缺少kill(pid, SIGCONT)),重复设置闹钟会覆盖定时。
  • waitpid阻塞:主进程调用waitpid(pid, nullptr, 0)会一直阻塞到子进程结束,无法循环执行定时中断。
  • 参数检查缺失:直接访问argv[1]未做argc判断,易导致崩溃。
  • 语法错误:cerr << "error << endl;存在字符串闭合错误。

修复后的代码

#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <cstring>
#include <fcntl.h>
#include <errno.h>

using namespace std;
using namespace chrono;

int pid;
bool user_responded = false;

void alarm_handler(int signum) {
    cout << "\n程序B已中断,请在5秒内按任意键恢复,否则将终止所有程序\n";
    kill(pid, SIGSTOP);
    user_responded = false;

    // 设置超时闹钟
    alarm(5);
    // 将标准输入设为非阻塞模式
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    char c;
    while (true) {
        if (read(STDIN_FILENO, &c, 1) > 0) {
            user_responded = true;
            kill(pid, SIGCONT);
            cout << "\n程序B已恢复运行\n";
            alarm(5); // 重新设置下一次中断
            break;
        }
        // 若超时被信号中断或用户已响应,退出循环
        if (user_responded) break;
        usleep(100000); // 降低CPU占用
    }

    // 恢复标准输入为阻塞模式
    fcntl(STDIN_FILENO, F_SETFL, flags);

    // 超时未响应,终止所有进程
    if (!user_responded) {
        cout << "\n超时未响应,终止程序A和B\n";
        kill(pid, SIGKILL);
        exit(0);
    }
}

int main(int argc, char* argv[]) {
    // 参数合法性检查
    if (argc < 2) {
        cerr << "用法: " << argv[0] << " <程序B路径> [参数]\n";
        cerr << "输入" << argv[0] << " help 查看帮助\n";
        return 1;
    }

    if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "h") == 0) {
        cout << "用法: " << argv[0] << " <程序B路径> [参数]\n";
        cout << "每5秒中断程序B,按任意键恢复;5秒未按键则终止所有程序\n";
        return 0;
    }

    // 设置信号处理
    signal(SIGALRM, alarm_handler);
    // 忽略Ctrl+C信号,避免直接终止主进程
    signal(SIGINT, SIG_IGN);

    pid = fork();
    if (pid == 0) {
        cout << "程序B名称: " << argv[1] << endl;
        cout << "程序B PID: " << getpid() << endl;
        execvp(argv[1], &argv[1]);
        // execvp执行失败时的错误处理
        cerr << "执行程序B失败: " << strerror(errno) << endl;
        exit(1);
    } else if (pid > 0) {
        cout << "程序A PID: " << getpid() << endl;
        high_resolution_clock::time_point t1 = high_resolution_clock::now();

        // 启动第一个5秒中断闹钟
        alarm(5);

        // 循环等待子进程状态,同时响应信号
        int status;
        while (waitpid(pid, &status, WNOHANG) == 0) {
            pause(); // 阻塞等待信号触发
        }

        high_resolution_clock::time_point t2 = high_resolution_clock::now();
        auto duration = duration_cast<milliseconds>(t2 - t1).count();
        cout << "总运行时间: " << duration << "ms" << endl;
    } else {
        cerr << "fork失败: " << strerror(errno) << endl;
        return 1;
    }

    return 0;
}

关键修复说明

  • 启动初始闹钟:主进程fork后立即调用alarm(5),触发第一次中断逻辑。
  • 非阻塞输入处理:用fcntl将标准输入设为非阻塞,配合usleep避免CPU空转,同时精准捕获用户按键。
  • 完善信号逻辑:中断后等待用户输入,按键则恢复进程并重新设置闹钟;超时则直接终止A和B。
  • 参数与错误处理:增加argc检查,处理fork、execvp的错误场景,修正原代码语法错误。

内容的提问来源于stack exchange,提问作者Raizel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 08:05:23