Parent等待linux shell上的前一个子进程

时间:2013-02-26 00:06:45

标签: c linux signals

我有一个程序可以分叉进程,并确定子进程是否应该在前台和后台运行。我叫信号函数在分叉前处理子信号,以确保死子进程不会变成僵尸。

到目前为止,我的程序工作正常,它会创建一个子进程并在用户输入带有'&'的命令时在后台运行它,并在用户输入没有'&'的命令时在前台运行它。

然而,我发现了一个非常有趣的行为。我支持这个操作序列:

sleep 5 &
ls

第一个命令将正常工作,父进程不等待睡眠5完成。但是,当我运行“ls”时,它会打印该文件夹中的所有文件(这很好),但是shell卡住了,等待之前的“睡眠5&”完成...

为什么会这样?我的子进程和父进程的代码(在分叉之后)看起来非常像下面这样:

 if (pid == 0)
 {
      // child process, execute stuff
      execv();
 } 
 else if (pid > 0) 
 {
      // parent process: call waitpid to wait for foreground child
 }

我试着做一些研究,但我找不到任何可以帮助我的东西。我尝试在子进程中使用“set session-id”,通过在execv()之前调用它,但它阻止我的子进程在终端上打印任何内容。 任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

    #define _XOPEN_SOURCE 700
    #include <unistd.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>

    void run_command(void)
    {
        char *cmd = NULL, *arg;
        size_t n, l;
        bool background;
        pid_t child;

        l = getline(&cmd, &n, stdin);
        cmd[l-1] = 0;
        l--;

        if (cmd[l-1] == '&') {
            background = true;
            cmd[l-1] = 0;
            l--;
        }
        else
            background = false;

        arg = strchr(cmd, ' ');
        if (arg) {
            *arg = 0;
            arg++;
        }

        child = fork();

        if (child) {
            if (!background)
                waitpid(child, NULL, 0);
        }
        else {
            execlp(cmd, cmd, arg, NULL);
            exit(-1);
        }

        free(cmd);
    }

    int main(void)
    {
        sigset_t set;
        struct sigaction sig;

        sigemptyset(&set);
        sig.sa_handler = SIG_DFL;
        sig.sa_mask = set;
        sig.sa_flags = SA_NOCLDWAIT;
        sigaction(SIGCHLD, &sig, NULL);

        while(!feof(stdin)) run_command();
    }

这可以按预期工作:

hdante@aielwaste:~/code$ ./shell 
pwd
/home/hdante/code
ls /home
hdante
sleep 5
ls /
bin    dev   initrd.img      lib32   lost+found  opt   run      srv  usr      vmlinuz.old
boot   etc   initrd.img.old  lib64   media       proc  sbin     sys  var
cdrom  home  lib         libnss3.so  mnt         root  selinux  tmp  vmlinuz
sleep 5&
xedit&
ls /
bin    dev   initrd.img      lib32   lost+found  opt   run      srv  usr      vmlinuz.old
boot   etc   initrd.img.old  lib64   media       proc  sbin     sys  var
cdrom  home  lib         libnss3.so  mnt         root  selinux  tmp  vmlinuz

在上面的示例中,睡眠5正确阻止,而睡眠5&amp;和xedit&amp;不。

不看你的代码,就不可能知道问题出在哪里。但请注意我处理僵尸进程的方式:我在sa_flags中使用SA_NOCLDWAIT,因此我不需要跟踪pids。另外,我使用waitpid()等待前台子进程。这就是我认为问题所在。您的代码可能正在调用wait()而不是waitpid()。区别在于wait()等待所有孩子。