代码之家  ›  专栏  ›  技术社区  ›  Martin

调用系统后如何启用ctrl-c/ctrl+break?

  •  2
  • Martin  · 技术社区  · 14 年前

    我编写了一个从内部调用系统命令的程序:

    #include <stdlib.h>
    
    int main(void)
    {
        while(1)
        {
            system("ls 2>&1 1>/dev/null"); // comment this line out to enable ctrl+break
        }
    
        return 0;
    }
    

    但是,当它运行时,CTRL+C和CTRL+BREAK不再工作,似乎被忽略了。

    我试图编写一个程序,在后台执行一些涉及shell的操作,但我也希望能够在用户想要中断时中断程序。

    3 回复  |  直到 14 年前
        1
  •  6
  •   Brian Campbell Dennis Williamson    14 年前

    POSIX specification for system() :

    系统() 系统() 如果命令由于接收到信号而终止,则采取适合应用程序的任何操作。

    因此,为了正确响应信号,需要检查 系统() .

    system()以指定的格式返回命令语言解释器的终止状态 waitpid()

    waitpid() 参考文档了解 wait() ,指示您使用以下宏找出进程退出的原因:

    • 未婚妻(stat_val)
      如果为正常终止的子进程返回状态,则计算结果为非零值。

    • 如果WIFEXITED(stat\u val)的值非零,则此宏将计算子进程传递给_exit()或exit()的状态参数的低位8位,或子进程从main()返回的值。
    • WIFSIGNALED(状态值)
    • WTERMSIG(统计值)
      如果WIFSIGNALED(stat\ val)的值不为零,则此宏将计算导致子进程终止的信号数。

    • 如果为当前已停止的子进程返回状态,则计算结果为非零值。
    • WSTOPSIG(状态值)
    • WIFCONTINUED(状态值)
      如果为从作业控制停止继续的子进程返回状态,则计算结果为非零值。

    #include <stdlib.h>
    #include <stdio.h>
    
    int main(void)
    {
        while(1)
        {
            int result = system("ls 2>&1 1>/dev/null");
            if (WIFEXITED(result)) {
              printf("Exited normally with status %d\n", WEXITSTATUS(result));
            } else if (WIFSIGNALED(result)) {
              printf("Exited with signal %d\n", WTERMSIG(result));
              exit(1);
            } else {
              printf("Not sure how we exited.\n");
            }
        }
    
        return 0;
    }
    

    如果你运行它,你会得到:

    $ ./sys
    Exited normally with status 0
    Exited normally with status 0
    Exited normally with status 0
    Exited normally with status 0
    Exited normally with status 0
    Exited normally with status 0
    ^CExited with signal 2
    
        2
  •  2
  •   Community CDub    5 年前

    IEEE Std 1003.1-2008 (POSIX) :

    • 这个 system() 函数的行为应类似于子进程是使用 fork() , ...

    • 系统() 功能 SIGINT SIGQUIT 信号 ,并应在等待命令终止时阻止SIGCHLD信号。如果这可能会导致应用程序丢失一个可能会杀死它的信号,那么应用程序应该检查 系统()

    • 这个 系统()

        3
  •  1
  •   Martin    14 年前

    根据圣哈辛托的上述评论:

    system()本质上是分叉、阻塞父级,并忽略子级中的某些信号,如POSIX规范链接所示。您可以先为system()创建另一个要阻止的进程来绕过此操作。这使得原始进程(shell所运行的进程的祖辈)可以自由地接受kill信号。

    #include <stdlib.h>
    #include <unistd.h>
    #include <wait.h>
    
    int main(void)
    {
        pid_t pid;
    
        while(1)
        {
            pid = fork();
    
            if(pid > 0) // parent
            {
                wait(0);
            }
            else if(pid == 0) // child
            {
                system("ls 2>&1 1>/dev/null");
                return 0;
            }
            else // could not fork
            {
                return 1;
            }
        }
    
        return 0;
    }
    

    表面上看,这似乎是我需要的。