2

私はcにUNIX配管を実装しようとしています(つまり、ls | wcを実行します)。問題に関連する解決策(C Unix Pipes Example)を見つけましたが、解決されたコードスニペットの特定の部分が機能する理由がわかりません。

コードは次のとおりです。

/* Run WC. */
int filedes[2];
pipe(filedes);

/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
    /* Set stdout to the input side of the pipe, and run 'ls'. */
    dup2(filedes[1], 1);
    char *argv[] = {"ls", NULL};
    execv("/bin/ls", argv);
 } else {
    /* Close the input side of the pipe, to prevent it staying open. */
     close(filedes[1]);
 }

 /* Run WC. */
 pid = fork();
 if (pid == 0) {
      dup2(filedes[0], 0);
      char *argv[] = {"wc", NULL};
      execv("/usr/bin/wc", argv);
  }

wcコマンドを実行する子プロセスでは、stndinをファイル記述子にアタッチしますが、最初の子プロセスでlsによって生成された出力を明示的に読み取っていないようです。したがって、wcの実行時にlsの出力を明示的に使用しないため、lsは独立して実行され、wcは独立して実行されているように見えます。では、このコードはどのように機能しますか(つまり、ls | wcを実行します)?

4

1 に答える 1

3

lsフォークされた子は、実行されたプロセスが書き込み(の場合)および読み取り(の場合)するファイル記述子を保証するため、表示されたコードはほぼ機能します(多くのコーナーをカットしますが、機能しますwc) 。パイプの適切な端です。もうする必要はありません。標準入力はファイル記述子0であるためwc、(ファイル名)引数なしで標準入力から読み取ります。 lsエラーメッセージを書き込んでいない限り、常に標準出力であるファイル記述子1に書き込みます。

コードスニペットには3つのプロセスがあります。親プロセスと2つの子(それぞれから1つずつ)fork()。親プロセスは、パイプの両端も閉じる必要があります。1つだけ閉じます。

一般に、パイプファイル記述子を実行dup()またはdup2()呼び出した後、パイプの両端を閉じる必要があります。lsデータを生成して終了するので、ここでそれを回避します。すべての状況でそうなるわけではありません。

コメント:

/* Set stdout to the input side of the pipe, and run 'ls'. */

不正確です。stdout入力側ではなく、パイプの出力側に設定しています。

execv()呼び出し後にエラーが終了するはずです。それらが失敗した場合、それらは戻り、プロセスは大混乱を引き起こす可能性があります(たとえば、ls失敗した場合、2つのコピーがwc実行されることになります。

SSCCE _

各プロセスでパイプの両端を注意深く閉じることに注意してください。親プロセスは、両方の子を起動すると、パイプを使用できなくなります。早い段階で閉じるコードを残しました(ただし、次のコードも実行された場合にのみ実行されたためfiledes[1]、明示的なブロックから削除しました)。ファイルを閉じる必要がある3つのコードパスのそれぞれにペアを保持していた可能性があります。elseelsecloses()

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int filedes[2];
    int corpse;
    int status;
    pipe(filedes);

    /* Run LS. */
    pid_t pid = fork();
    if (pid == 0)
    {
        /* Set stdout to the output side of the pipe, and run 'ls'. */
        dup2(filedes[1], 1);
        close(filedes[1]);
        close(filedes[0]);
        char *argv[] = {"ls", NULL};
        execv("/bin/ls", argv);
        fprintf(stderr, "Failed to execute /bin/ls\n");
        exit(1);
    }
    /* Close the input side of the pipe, to prevent it staying open. */
    close(filedes[1]);

    /* Run WC. */
    pid = fork();
    if (pid == 0)
    {
        /* Set stdin to the input side of the pipe, and run 'wc'. */
        dup2(filedes[0], 0);
        close(filedes[0]);
        char *argv[] = {"wc", NULL};
        execv("/usr/bin/wc", argv);
        fprintf(stderr, "Failed to execute /usr/bin/wc\n");
        exit(1);
    }

    close(filedes[0]);

    while ((corpse = waitpid(-1, &status, 0)) > 0)
        printf("PID %d died 0x%.4X\n", corpse, status);
    return(0);

}

出力例:

$ ./pipes-14312939
      32      32     389
PID 75954 died 0x0000
PID 75955 died 0x0000
$
于 2013-01-14T03:51:25.240 に答える