在linux上使用c++实现调用子进程等待超时功能

本文详细介绍了在Linux上使用C++如何实现调用子进程并设置等待超时功能,包括waitpid函数的作用、参数、WNOHANG选项的使用,以及如何在Linux环境下模拟Windows的WaitForSingleObject API。文章还讨论了SIGCHID信号、系统调用system的实现和潜在问题,并提供了增加超时机制的shell命令执行示例。
摘要由CSDN通过智能技术生成

在linux上使用c++实现调用子进程等待超时功能

waitpid函数的作用

waitpid() 函数实际上用于等待子进程的状态变化,并为父进程提供子进程的终止状态信息。当一个子进程终止时,操作系统会向父进程发送 SIGCHLD 信号。在处理这个信号的过程中,父进程通常会使用 waitpid() 函数来获取子进程的状态信息,以便执行相应的操作(如回收资源)。

waitpid() 函数可以等待子进程的以下几种状态变化:

  1. 子进程正常终止:子进程执行完毕或调用 exit() 函数。
  2. 子进程被信号终止:子进程因接收到一个信号(如 SIGKILL)而被终止。
  3. 子进程被暂停:当使用 WUNTRACED 选项时,waitpid() 函数还可以返回因接收到 SIGSTOP 而暂停的子进程的状态。
  4. 子进程恢复执行:当使用 WCONTINUED 选项时,waitpid() 函数还可以返回因接收到 SIGCONT 而恢复执行的子进程的状态。

waitpid() 函数的功能不仅限于等待 SIGCHLD 信号。它实际上为父进程提供了一种在子进程状态变化时收集信息和执行操作的机制。这有助于避免僵尸进程的产生,并允许父进程对子进程的状态变化做出响应。

函数原型

waitpid() 函数是一个用于等待子进程状态变化的系统调用。它可以让父进程在子进程结束时收到通知,从而避免僵尸进程的产生。waitpid() 函数的原型如下:

#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

参数说明:

  1. pid:指定要等待的子进程的进程 ID。有以下几种取值:
  • pid > 0:等待指定 PID 的子进程。
  • pid == -1:等待任何子进程。此时,waitpid() 的行为类似于 wait() 函数。
  • pid == 0:等待同一进程组中的任何子进程。
  • pid < -1:等待指定进程组 ID 的绝对值的任何子进程。
  1. status:一个指向整数的指针,用于存储子进程的终止状态。您可以使用一些宏(如 WIFEXITEDWEXITSTATUS 等)来分析这个状态值。
  2. options:提供额外的选项来控制 waitpid() 函数的行为。主要有以下几种选项:
  • WNOHANG:使 waitpid() 函数在没有子进程终止时立即返回,而不会阻塞。
  • WUNTRACED:除了已终止的子进程外,还返回因接收到 SIGSTOP 而停止的子进程的状态。
  • WCONTINUED:返回因接收到 SIGCONT 而继续运行的子进程的状态。
  1. 返回值:
  • 如果成功,waitpid() 函数返回一个子进程的进程 ID。
  • 如果使用了 WNOHANG 选项且没有子进程已经终止,waitpid() 函数返回 0。
  • 如果发生错误,waitpid() 函数返回 -1,并设置 errno

在信号处理函数中使用 waitpid() 函数和 WNOHANG 选项的一个典型场景是处理子进程终止时发送的 SIGCHLD 信号。通过在信号处理函数中使用循环,您可以确保在一次信号处理函数调用中处理所有已终止的子进程。这种方法在多个 SIGCHLD 信号被合并的情况下尤其有效,能避免僵尸进程的产生。

WNOHANG 参数的作用

如果两个子进程几乎同时终止,它们各自发送的 SIGCHLD 信号可能会被合并为一个信号,导致信号处理函数只被调用一次。然而,通过在信号处理函数中使用 waitpid() 函数并设置 WNOHANG 选项,您仍然可以处理这种情况。

WNOHANG 选项本身并不能保证处理所有子进程。然而,在信号处理函数(如catch_child())中使用一个循环可以确保处理所有已终止的子进程。

当您在信号处理函数中使用如下循环时:

pid_t wpid;
int status;
while ((wpid = waitpid(-1, &status, WNOHANG)) > 0) {
   
    if (WIFEXITED(status)) {
   
        printf("-----------catch child id=%d, status=%d\n", wpid, WEXITSTATUS(status));
    }
}

waitpid() 函数会立即返回,而不会等待子进程终止。循环会检查是否有子进程已经终止,如果有,waitpid() 函数将返回已终止子进程的 PID。当没有更多子进程终止时,waitpid() 会返回 0,并退出循环。

这个循环会在有子进程终止时执行。只要 waitpid() 函数返回的值大于 0,意味着有子进程已经终止,循环将继续执行。当没有更多子进程终止时,waitpid() 会返回 0,并退出循环。

虽然 WNOHANG 选项并不知道有多少个子进程,但这个循环确保了处理所有已终止的子进程。只要有子进程终止,循环将继续执行,直到处理所有子进程。这种方法能够确保在一次信号处理函数调用中处理所有已终止的子进程,避免僵尸进程的产生。

这样一来,即使多个 SIGCHLD 信号被合并,您仍然可以通过这个循环找出所有已终止的子进程,并执行相应的操作。这种方法能够确保在一次信号处理函数调用中处理所有已终止的子进程,避免僵尸进程的产生。

SIGCHID信号

SIGCHLD 信号是一个由操作系统发送给父进程的信号,用于通知父进程子进程状态的变化。当子进程终止、被暂停或恢复时,操作系统会向父进程发送 SIGCHLD 信号。这使得父进程能够得知子进程的状态变化并采取适当的措施,如回收资源,避免僵尸进程的产生。

以下是 SIGCHLD 信号的一些主要用途:

  1. 子进程终止:当子进程正常终止(例如执行完成或调用 exit() 函数)或异常终止(例如收到一个致命信号)时,操作系统会向父进程发送 SIGCHLD 信号。在这种情况下,父进程可以通过调用 wait()waitpid() 函数来回收子进程的资源,以及获取子进程的终止状态。
  2. 子进程被暂停:当子进程因收到 SIGSTOP 信号而被暂停时,操作系统会向父进程发送SIGCHLD 信号。父进程可以通过调用 waitpid() 函数并使用 WUNTRACED 选项来检测子进程的暂停状态。
  3. 子进程恢复:当子进程因收到 SIGCONT 信号而恢复执行时,操作系统会向父进程发送 SIGCHLD 信号。父进程可以通过调用waitpid() 函数并使用 WCONTINUED 选项来检测子进程的恢复状态。

默认情况下,当进程收到 SIGCHLD 信号时,信号会被忽略。但是,您可以为 SIGCHLD 信号定义一个信号处理函数来处理子进程的状态变化。这样,在子进程终止或状态发生变化时,信号处理函数会被自动调用,您可以在其中执行相应的操作。

总之,SIGCHLD 信号是一种通知机制,用于告知父进程其子进程状态的变化。这使得父进程能够采取适当的措施,如回收资源和避免僵尸进程的产生。

在linux环境下实现windows中WaitForSingleObject的API

在c++程序的编写中,经常会出现调用外部程序的情况,在windows中可以通过下面的代码来实现:

int RunExe(char *cmd, char *datdir, int limitsec) {
   

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;

    if (!CreateProcess(NULL, cmd, NULL, NULL, true, 0, NULL, datdir, &si, &pi)) {
   
        return -1;
    }

    g_childProcessHandle.push_back(pi.hProcess);

    DWORD exitcode;
    int count=0;
    do {
   
        if(limitsec==-1)
            WaitForSingleObject(pi.hProcess, INFINITE);
        else
            WaitForSingleObject(pi.hProcess, limitsec*1000);

        GetExitCodeProcess(pi.hProcess,&exitcode);
        TerminateProcess(pi.hProcess,1);
        count++;
    }while(exitcode==28 && count<2);


    auto pos = find(g_childProcessHandle
  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sususweet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值