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

How to send SIGINT to background processes only in C

本文关键字:后台进程 SIGINT 何仅      更新时间:2023-10-16

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

  1. 使用setpgid(0,0)创建仅由后台进程组成的进程组在pid=fork()为0的子句中,即当我要执行子进程时
  2. 我在setpgid(0,0)语句之后得到的进程组"pgid",我在kill函数中使用,如kill(pgid, 2)

不幸的是,整个程序被中断,后台任务仍在运行。

以下是相关代码:

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
            }
        }               
    }  
}

我做错了什么?

只是猜测。。。1) 你是否确保你的主要流程是不同团队的一部分?2) 一旦您的孩子因stdin/stdout/stderr连接而死亡,您的父母可能会收到SIGPIPE。SIGPIPE的默认信号操作是终止(参见信号(7))。

查看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。