2013-02-26 22 views
0

我有一个程序分叉一个进程,并确定子进程是否应该在前台和后台运行。我称之为信号函数来处理分岔之前的子信号,以确保死亡子进程不会变成僵尸。家长在linux shell上等待以前的子进程

到目前为止,我的程序正常工作,它会创建一个子进程,每当用户输入与“&”命令,运行它的背景,每当用户输入而不“&”命令,运行它的前景。

但是,我发现了一个非常有趣的行为。提供我称为这个操作序列:

sleep 5 & 
ls 

第一个命令将正常工作,父进程不会等待睡眠5完成。但是,当我运行“ls”时,它会打印该文件夹中的所有文件(这很好),但随后外壳卡住了,等待先前的“睡眠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()之前调用它,但它阻止了我的子进程在终端上打印任何内容。 任何帮助将不胜感激。谢谢!

+0

有很多可能性。没有看到更多的代码,很难猜测问题。 – 2013-02-26 00:31:36

回答

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(); 
    } 

这按预期方式工作:

[email protected]:~/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 &和XEDIT &没有。

不看你的代码,就不可能知道问题出在哪里。不过要注意我处理僵尸进程的方式:我在sa_flags中使用SA_NOCLDWAIT,这样我就不需要跟踪pid了。另外,我使用waitpid()等待前台子进程。这就是我认为问题所在。很可能你的代码调用了wait()而不是waitpid()。不同的是wait()等待所有的孩子。