【问题标题】:How to cancel an alarm() signal via a child process?如何通过子进程取消警报()信号?
【发布时间】:2012-04-19 23:45:09
【问题描述】:

对于一项任务,我正在创建一个时间感知外壳。如果命令运行超过设定的时间,shell 会分叉并执行命令并杀死它们。例如。

 input# /bin/ls
 a.out code.c
 input# /bin/cat
 Error - Expired After 10 Seconds.
 input#

现在,我的问题是:如果在程序的处理过程中发生错误,即exevce返回-1时,有没有办法防止警报启动?

由于子进程是单独运行的,经过数小时的试验和研究,我还没有找到任何讨论甚至暗示这类任务的东西,我觉得这可能是不可能的。如果确实不可能,我该如何防止发生类似以下的事情......

 input# /bin/fgdsfgs
 Error executing program
 input# Error - Expired After 10 Seconds.

对于上下文,这是我目前正在使用的代码,我自己尝试这样做的尝试已被删除。提前感谢您的帮助!

while(1){
    write(1, prompt, sizeof(prompt)); //Prompt user
    byteCount = read(0, cmd, 1024); //Retrieve command from user, and count bytes
    cmd[byteCount-1] = '\0';    //Prepare command for execution

    //Create Thread
    child = fork();

    if(child == -1){
        write(2, error_fork, sizeof(error_fork));
    }

    if(child == 0){ //Working in child
        if(-1 == execve(cmd,arg,env)){  //Execute program or error
            write(2, error_exe, sizeof(error_exe));
        }   
    }else if(child != 0){   //Working in the parent
        signal(SIGALRM, handler);   //Handle the alarm when it goes off
        alarm(time);
        wait();
        alarm(0);
    }
}

【问题讨论】:

    标签: c signals alarm child-process


    【解决方案1】:

    根据man page

    说明

    alarm() 函数应使系统在经过 seconds 指定的实时秒数后为进程生成 SIGALRM 信号。处理器调度延迟可能会阻止进程在信号生成后立即对其进行处理。

    如果秒为 0,则取消挂起的警报请求(如果有)。

    警报请求不堆叠;以这种方式只能调度一个 SIGALRM 生成。如果尚未生成 SIGALRM 信号,则调用将导致重新安排生成 SIGALRM 信号的时间。

    alarm() 与 setitimer()、ualarm() 或 usleep() 中的任何一个之间的交互是未指定的。

    所以,要取消警报:alarm(0)。它甚至出现在您的示例代码中。

    主要问题

    顺便说一句,你在这里错过了一个重要的部分:

    if(child == 0){ //Working in child
        if(-1 == execve(cmd,arg,env)){  //Execute program or error
            write(2, error_exe, sizeof(error_exe));
            _exit(EXIT_FAILURE);  // EXIT OR A FORKED SHELL WILL KEEP GOING
        }   
    }else if(child != 0){   //Working in the parent
    

    【讨论】:

    • 对了,我代码中的alarm(0)成功取消了子进程执行成功时的报警;因此,当在 x 秒计时器到期之前执行命令时,警报不会响起。不幸的是,这不是进程无法执行时发生的行为。 编辑:感谢第二个提示!
    • 我在回答后才意识到。但是当execve() 失败时缺少exit() 似乎是暗示。
    • 如果execve 失败,您必须_exit 而不是exit。后者通常是不安全的。
    • @R..:好吧,如果没有任何与atexit() 挂钩的操作,那么它们之间的区别是微妙的。但无论如何我都会编辑答案,因为正如你所说,在这种情况下它是一个更好的选择(+1 为你)。
    【解决方案2】:

    wait() 系统调用带有一个参数;为什么不使用源文件中的正确标头和未声明函数的编译器警告(最好是错误)进行编译?或者,如果您收到此类警告,请在提交代码以供在 StackOverflow 等地方进行审核之前注意它们。

    您不需要测试来自execve()(或任何exec*() 函数)的返回状态;如果返回,则失败。

    在失败时写一个错误是好的。如果子进程也退出会更好,这样它就不会回到while (1)循环,与你的主shell竞争输入数据。

    if (child == 0)
    {
        execve(cmd, arg, env);
        write(2, error_exe, sizeof(error_exe));
        exit((errno == ENOEXEC) ? 126 : 127);
    }
    

    事实上,孩子不出门是造成问题的主要原因;由于孩子尚未退出,因此等待不会返回,直到警报响起。显示的退出状态旨在匹配 POSIX shell 规范。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多