c - 一旦超过时间限制就终止进程

标签 c kill-process waitpid

我已经在下面的代码上工作了很长一段时间,但无法真正弄明白。 任务是读取终端命令并每 x 秒运行一次;如果命令在等待时间内没有完成,我们想终止进程,然后再次运行命令。 任何帮助将非常感激。 我很确定我没有正确使用 waitpid();我将如何使用 waitpid 来实现目标?

此外,我将如何检测子进程中的错误?计划是在子进程发生错误时终止父进程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>

/*
 * 
 */
int main(int argc, char** argv) {
    int waitingTime;
    if (argc < 3) {
        printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
        return (EXIT_FAILURE);
    } 
    // -n parameter specified? If so, set the waiting time.
    if (argc == 5 && strcmp(argv[3], "-n") == 0) {
        waitingTime = atoi(argv[4]);
    } else {
        waitingTime = 5; // Default waiting time.
    }

    char* cmd = (char*)malloc(sizeof(argv[1]));
    cmd = argv[1];
    char* param = (char*)malloc(sizeof(argv[2]));
    param = argv[2];

    // Print the read command and its param
    printf("Command: %s, Parameter: %s, Interval: %d\n\n", cmd, param, waitingTime);    

    pid_t pid;

    for (;;) { 
        // Declared here for scope
        int secsWaited;
        secsWaited = 0;
        pid = fork();

        if (pid == 0) {
            pid = getpid();
            printf("==============\n");
            execlp(cmd, cmd, param, "/", (char *)NULL);
            printf("Excec failed; killing the proccess.");
            kill(pid, SIGKILL);
        } else if (pid > 0) {
            int status, code;
            for (;;) {
                code = waitpid(pid, &status, WNOHANG);
            if (code == 0 && secsWaited >= waitingTime) {
                kill(pid, SIGKILL);
            printf("Child stopped");
            break;
        } else if (code == 0 && secsWaited < waitingTime) {
            secsWaited++;   
                    sleep(1);
                } else {
                    break;
                }
            }

            /*if (!WIFEXITED(status)) {
                printf("Time exceeding, stopping child.");
        // Get parent process id and kill it.
        kill(getpid(), SIGKILL);
        }*/



            // Sleep for the specified time
            sleep(waitingTime - secsWaited);

        } else {
            return (EXIT_FAILURE);
        }

    }      

    free(cmd);
    free(param);       
    return (EXIT_SUCCESS);
}

最佳答案

您的逻辑有点太复杂了(例如,太多不同的 sleep 调用和 if/else 梯形图逻辑)。

此外,无需malloc argv 字符串——它们可以直接使用。

我对其进行了简化并进行了一些重组以使其正常工作[请原谅不必要的样式清理]:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>

/*
 *
 */
int
main(int argc, char **argv)
{
    int waitingTime;

    if (argc < 3) {
        printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
        return (EXIT_FAILURE);
    }
    // -n parameter specified? If so, set the waiting time.
    if (argc == 5 && strcmp(argv[3], "-n") == 0) {
        waitingTime = atoi(argv[4]);
    }
    else {
        waitingTime = 5;                // Default waiting time.
    }

    char *cmd = argv[1];
    char *param = argv[2];

    // Print the read command and its param
    printf("Command: %s, Parameter: %s, Interval: %d\n\n",
        cmd, param, waitingTime);

    pid_t pid;
    int code = -1;
    int status;
    int killflg = 1;

    for (;;) {
        // Declared here for scope
        int secsWaited;

        secsWaited = 0;
        pid = fork();

        // stop on fork failure
        if (pid < 0) {
            killflg = 1;
            break;
        }

        // child process
        if (pid == 0) {
            pid = getpid();
            printf("==============\n");
#if 0
            execlp(cmd, cmd, param, "/", (char *) NULL);
#else
            execlp(cmd, cmd, param, (char *) NULL);
#endif
            printf("Excec failed; killing the proccess.");

// NOTE/BUG: this is the child so pid is zero, so killing it is wrong
#if 0
            kill(pid, SIGKILL);
#else
            exit(1);
#endif
        }

        killflg = 0;
        for (;;) {
            code = waitpid(pid, &status, WNOHANG);
            if (code > 0)
                break;

            if (killflg)
                continue;

            secsWaited++;
            sleep(1);

            if (secsWaited >= waitingTime) {
                printf("timeout\n");
                kill(pid, SIGKILL);
                killflg = 1;
            }
        }

        if (! killflg)
            break;
    }

#if 0
    free(cmd);
    free(param);
#endif

    if (killflg)
        code = EXIT_FAILURE;
    else
        code = EXIT_SUCCESS;

    return code;
}

更新:

Right now, the program will stop after one iteration; if I remove the breakpoint at if (! killflg), it will work as expected. Am I missing something or is this just a misunderstanding?

你是对的——我的错。我在你的问题中遗漏了以下内容:

The task is to read a terminal command and to run it every x seconds;

break 更改为 sleep(waitingTime - secsWaited)


但是,一种更可靠的跟踪耗时的方法可能是通过两次调用 time(2):

killflg = 0 之后,执行:time_t todbeg = time(NULL); time_t todelap;.然后,您可以 [anywhere] 使用以下方法获取耗时:todelap = time(NULL) - todbeg; [此处,todelap 类似于 secsWaited ].这可能比增加 secsWaited 更好。

time 只有秒分辨率。要获得更精确的控制,请考虑使用 clock_gettime [具有纳秒分辨率]。

这里有一个函数,我经常用它来计算耗时 [in fractional seconds]:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>

double
tvgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_REALTIME,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    return sec;
}

/*
 *
 */
int
main(int argc, char **argv)
{
    int waitingTime;

    if (argc < 3) {
        printf("Invalid number of arguments provided. Please specify a command and exactly one parameter.");
        return (EXIT_FAILURE);
    }
    // -n parameter specified? If so, set the waiting time.
    if (argc == 5 && strcmp(argv[3], "-n") == 0) {
        waitingTime = atoi(argv[4]);
    }
    else {
        waitingTime = 5;                // Default waiting time.
    }

    char *cmd = argv[1];
    char *param = argv[2];

    // Print the read command and its param
    printf("Command: %s, Parameter: %s, Interval: %d\n\n", cmd, param, waitingTime);

    pid_t pid;
    int code = -1;
    int status;
    int killflg = 1;
    double todzero = tvgetf();

    for (;;) {
        // Declared here for scope
        double todbeg = tvgetf();
        double todelap;

        pid = fork();

        // stop on fork failure
        if (pid < 0) {
            killflg = 1;
            break;
        }

        // child process
        if (pid == 0) {
            pid = getpid();
            printf("============== (%.9f)\n",tvgetf() - todzero);
            execlp(cmd, cmd, param, (char *) NULL);
            printf("Excec failed; killing the proccess.");
            exit(1);
        }

        killflg = 0;
        for (;;) {
            code = waitpid(pid, &status, WNOHANG);
            if (code > 0)
                break;

            if (killflg)
                continue;

            usleep(1000);

            todelap = tvgetf() - todbeg;
            if (todelap >= waitingTime) {
                printf("timeout\n");
                kill(pid, SIGKILL);
                killflg = 1;
            }
        }

        // do _not_ wait -- we already timed out
        if (killflg)
            continue;

        // get final elapsed time for this round and the amount of time
        // remaining until the next interval
        todelap = tvgetf() - todbeg;
        useconds_t time_to_wait = ((double) waitingTime - todelap) * 1e6;

        // wait until the next time period
        if (time_to_wait > 0)
            usleep(time_to_wait);
    }

    if (killflg)
        code = EXIT_FAILURE;
    else
        code = EXIT_SUCCESS;

    return code;
}

旁注:我在这里使用了 usleep,但是,虽然稍微复杂一些,但人们认为使用 nanosleep

会更好

关于c - 一旦超过时间限制就终止进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53403120/

相关文章:

linux - 为什么waitpid(2)可以指定非子进程?

c - C 标准是否禁止重新声明?

嵌套取消引用的成本可以忽略不计吗?

windows - 如何杀死 node.js 上的打开进程?

linux - 自动杀死进程 - linux

c - WSTOPSIG(状态) == 22 & WTERMSIG(状态) == 9;这些数字从何而来?

c - 为什么 get_long_long ("") 打印两次?

c - 面试Hello World讲解

emacs - 如何删除 Emacs 在关闭时创建的以 '#' 开头和结尾的临时文件?

c - 管道和流程管理