杀死运行系统 shell 命令的子进程

Posted

技术标签:

【中文标题】杀死运行系统 shell 命令的子进程【英文标题】:Kill a child process running a system shell command 【发布时间】:2014-04-17 21:23:58 【问题描述】:

在我的父进程中,我创建了一个执行 system("find / -print") 的子进程。 从父级内部,当我尝试使用 kill(childProcPID, SIGTERM) 杀死这个子进程时,它不会立即终止。 system 命令继续在控制台上打印输出。

示例代码如下:

int main(void) 

    pid_t childProc = fork();
    switch (childProc) 
    case -1:
        perror("fork() error");
        exit(EXIT_FAILURE);
    case 0:
        system("find / -print");
        printf("if I use kill(pid, SIGTERM) control doesnt reach here");
        exit(EXIT_SUCCESS);
    default:
        ;
        int i = 500000;

        //No a great way to put sleep
        //but its just temp
        while (i != 0) 
            --i;
        

        kill(childProc, SIGTERM);
        break;
    

    printf("Exit!!!!!!");
    return EXIT_SUCCESS;

请让我知道我做错了什么或者是杀死孩子的正确方法?

【问题讨论】:

SIGKILL 可能是一个选项。 使用 SIGKILL,我得到相同的结果 有可能孩子甚至没有跑步。尝试使用 sleep(1) 而不是你的忙循环。它在<unistd.h> 实际上,当我运行这个程序时,我看到输出连续写在屏幕上。所以,我猜系统命令仍在运行。 我猜该程序已经完成,而您所看到的只是 I/O 子系统的输出缓冲区清空。尝试按 CTRL-O,看看是否设置为刷新。 【参考方案1】:

system 函数将自己创建一个子进程来执行命令(然后阻塞直到该子进程终止)。您所做的是杀死调用system 的子进程,而不是杀死system 产生的子进程。

【讨论】:

您确定该信号没有升级回父进程吗?换句话说,系统是否使用 setsid() 来渲染一个新的进程会话? 但是无论如何,这暗示你应该使用system,而不是使用exec 我也觉得系统创建了自己的子线程。也许我应该使用 exec 家族函数 @Vinit Sharma:如果你想控制是否过早终止进程,你不能使用system。您必须使用exec 函数之一。 @Vinit Sharma:cd 等 Shell 命令不起作用,但实际程序可以。请注意execlpexecvp 接受文件名(因此它接受find 而不是/usr/bin/find)。它搜索的路径取决于您的程序的环境变量。【参考方案2】:

尝试设置会话 ID 并终止进程组(man 2 kill)

int main(void) 

pid_t childProc = fork();
switch (childProc) 
case -1:
    perror("fork() error");
    exit(EXIT_FAILURE);
case 0:
    setsid();
    system("find / -print" );
    printf("if I use kill(pid, SIGTERM) control doesnt reach here");
    exit(EXIT_SUCCESS);
default:
    sleep(1);
    kill(childProc*-1, SIGTERM);
    break;


printf("Exit!!!!!!");
return EXIT_SUCCESS;

这或多或少有效。需要注意的是,父母必须给孩子时间 setid(),因此需要睡眠。

希望对您有所帮助。

【讨论】:

是的,它确实有效......但我只是想知道它是否会导致任何其他问题? @Vinit Sharma:这个解决方案没有问题。我要说的是你不应该依赖sleep 来避免竞争条件,但在这种情况下,多久调用kill 并不重要。但是,使用exec 函数不是更优雅吗?在这里,您正在创建一个新会话,以便您可以将进程作为一个组终止。 @Vinit Sharma。你不会有额外的问题。它只会杀死进程组中的进程。但是,您也应该随意尝试 exec 函数。但是,您可能会发现,根据您对它们调用的内容,您可能仍需要 setid() 以确保传播到可能产生的任何后续第三级子级。 @someguy:谢谢..我没有在我的实际代码中使用睡眠功能......它制作了这个程序,这样我就不必复制粘贴确切的代码了。我也在试验 exec 函数。非常感谢您的投入。 @maha:非常感谢您的解释。【参考方案3】:

首先,您应该检查从kill() 返回的结果——如果返回 0,则操作成功。但是,如果返回 -1,请检查全局变量 errno 以了解问题所在。

如果信号发送成功,您唯一能做的就是确保您发送的是您想要的信号。正如@Till 在评论中指出的那样,发送SIGKILL instead of SIGTERM 会更有效,因为操作系统会处理前者,而目标进程不能忽略它。

无论如何,要意识到与其他进程的交互通常是一个异步进程——无论你做什么,目标进程都可能不会在kill() 返回时终止。

【讨论】:

感谢您的帮助,但它只是让这个程序显示我的问题。我知道我应该使用 kill 的返回值,我同意你的最后一点。

以上是关于杀死运行系统 shell 命令的子进程的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习-进程管理

Shell脚本入门 07:进程与信号

Shell脚本入门 07:进程与信号

创建一个不是创建进程子进程的新进程

shell多进程实例

终止正在运行的子进程调用