如何仅在C中将SIGINT发送到后台进程

时间:2015-03-02 17:20:05

标签: c++ c linux

我正在编写一个简单的shell程序,我可以在其中执行一些后台进程。我想使用像" killbg"这样的特定命令。能够SIGINT我执行的每个后台进程。我试过了:

  1. 使用setpgid(0,0)创建仅包含后台进程的进程组 在pid=fork()为0的条款中,即当我要执行子进程时。
  2. 流程小组' pgid'我得到setpgid(0,0)语句,我在kill函数中使用,如kill(pgid, 2)
  3. 不幸的是,整个程序被中断,后台任务仍在运行。

    以下是相关代码:

    while(1){
      fgets.. //user input for command
    
      // Kill background processes      
            if(strcmp(execArgs[0], "killbg") == 0){    //execArgs argument array for execve
                kill(pgid, 2); 
                perror("");
            }
            pid=fork();
    
            // Error in fork
            if(pid <= -1){
                perror("Error with fork.\n");
             exit(EXIT_FAILURE);
            }       
            // Child process
            else if(pid == 0){
                if(execBG == TRUE){    // execBG true If user wants to run command in background
                    setpgid(0,0);
                    pgid = getpgid(pid);
                }
                execve(execArgs[0], execArgs, NULL); 
                fprintf(stderr, "Not a valid command! Remember the full path.\n");  
    
            }
            // Parent process       
            else{
                if(execBG==FALSE){
                    waitpid(-1, &status, NULL);
                }
                else{
                    ;    // if background process, don't wait for the child
                }
            }               
        }  
    }
    

    我做错了什么?

2 个答案:

答案 0 :(得分:0)

猜猜...... 1)您确定您的主要流程是不同群体的一部分吗? 2)由于stdin / stdout / stderr连接,您的孩子一旦死亡,您的父母可能会收到一个SIGPIPE。 SIGPIPE的默认信号动作是终止(参见signal(7))。

答案 1 :(得分:0)

查看POSIX kill()函数的规范,了解如何向进程组发送信号:

  

如果 pid 大于0, sig 将被发送到进程ID等于 pid 的进程。

     

如果 pid 为0,则 sig 应发送到进程组ID等于进程组ID的所有进程(不包括未指定的系统进程集)发件人,并且该进程有权发送信号。

     

如果 pid 为-1,则 sig 将被发送到进程有权发送该信号的所有进程(不包括未指定的系统进程集)。

     

如果 pid 为负数,但不为-1,则应将 sig 发送给进程组ID等于的所有进程(不包括未指定的系统进程集) pid 的绝对值,并且该进程有权发送信号。

因此,要将SIGINT发送到流程组,您需要致电kill(-pgrp, SIGINT)。您还应该始终检查系统调用的返回值,以便了解它何时失败。

我发现如果execve()失败(也就是返回),则会打印错误消息 - 这很好!通常在此时退出程序也是正确的。否则,你往往会有一个额外的过程试图读取你的终端输入,这很容易混乱和混乱。

请注意,kill(pgrp, 2); perror("");不好,因为errno可以在调用kill()之前设置为非零值,或者kill()即使不报告失败也可以设置为非零值。您必须测试系统调用的返回值,以了解errno是否相关,如果相关,则只应调用perror()。 (这假设你应该打电话给perror(); IMO,这是错误报告功能的一个相当蹩脚的借口,但如果使用得当,它总比没有好。)

您的waitpid()电话不安全。第三个参数是整数,而不是指针。此外,您可以在后台运行多个子进程;该代码只等待一个退出 - 任何子进程。你几乎肯定需要一个循环,也可能需要WNOHANG。