0

プロセスをフォークし、子プロセスをフォアグラウンドとバックグラウンドで実行するかどうかを決定するプログラムがあります。シグナル関数を呼び出して、フォークする前に子シグナルを処理し、死んだ子プロセスがゾンビにならないようにします。

これまでのところ、プログラムは正常に動作し、ユーザーが「&」を使用してコマンドを入力するたびに子プロセスを作成してバックグラウンドで実行し、ユーザーが「&」を使用せずにコマンドを入力するたびにフォアグラウンドで実行します。

しかし、私は非常に興味深い行動を見つけました。この一連の操作を次のように呼び出したとします。

sleep 5 &
ls

最初のコマンドは正常に動作し、親プロセスはスリープ 5 が終了するのを待ちません。ただし、「ls」を実行すると、そのフォルダー内のすべてのファイルが出力されますが (これは良いことです)、シェルがスタックして、前の「sleep 5 &」が終了するのを待っています...

なぜこれが起こるのですか?子プロセスと親プロセスのコード (分岐後) は、次のようになります。

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

私はいくつかの研究を試みましたが、私を助けることができるものを見つけることができません. execv() の前に呼び出して、子プロセスに「set session-id」を使用しようとしましたが、子プロセスが端末に何かを出力できなくなります。どんな助けでも大歓迎です。ありがとう!

4

1 に答える 1

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

上記の例では、sleep 5 は正しくブロックしますが、sleep 5& と xedit& はブロックしません。

コードを見なければ、どこに問題があるかを知ることは不可能です。ただし、ゾンビ プロセスの処理方法に注意してください。pid を追跡する必要がないように、sa_flags で SA_NOCLDWAIT を使用します。また、waitpid() を使用してフォアグラウンドの子プロセスを待ちます。そして、そこが問題だと思います。コードが waitpid() ではなく wait() を呼び出している可能性があります。違いは、wait() がすべての子を待機することです。

于 2013-02-26T00:57:14.027 に答える