1

UNIX FIFO を使い始めたばかりで、最初の FIFO プログラムを試しているときに何かを発見しました。プログラムは次のように動作します。FIFO を作成した後、fork()関数を使用して 2 つのプロセスが開始されます。子プロセスは、父親が FIFO を介して彼に渡したものを読み取り、それを画面に出力します。交換されるデータは、引数として指定された文字列です。問題は、ファーザー セクションで、FIFO の入力側を閉じるのを忘れた場合 (close(fd)行を除外することを意味します)、プロセス間のデータが正しく交換されていても、プログラムがハングすることです。それ以外の場合は、すべて正常に動作し、プログラムはハングせずに終了します。誰かが私に理由を説明してもらえますか?

お待ち頂きまして、ありがとうございます。メイン関数のコードは次のとおりです。

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("An argument must be specified\n");
        return -1;
    }   

    int ret = mkfifo("./fifo.txt", 0644);
    char buf;

    if(ret < 0)
    {
        perror("Error creating FIFO");
        return -1;
    }

    pid_t pid = fork();

    if(pid < 0)
    {
        perror("Error creating child process");
        return -1;
    }

    if(pid == 0) /* child */
    {
        int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */

        while(read(fd, &buf, 1) > 0)
        {
            write(STDOUT_FILENO, &buf, 1);
        }
        write(STDOUT_FILENO, "\n", 1);
        close(fd);
        return 0;
    }
    else /* father */
    {
        int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */

        write(fd, argv[1], strlen(argv[1]));
        close(fd);
        waitpid(pid, NULL, 0);
        return 0;
    }
}
4

2 に答える 2

5

read(2)キャラクターが利用可能になるか、チャネルが反対側で閉じられるまでブロックします。最後の子プロセスread()が戻るには、親プロセスがパイプを閉じる必要があります。父親でを省略した場合、子供は父親が出るまでclose(fd)ブロックしますが (パイプは自動的に閉じます)、父親は子供が出るまで待機します。read()waitpid()

于 2011-01-12T14:44:51.917 に答える
0

まず最初に、投稿したコードにはいくつかの問題があります。

  1. ディレクティブがない#includeため、呼び出す関数のスコープ内にプロトタイプはありません。C89 では、次のような可変引数関数のプロトタイプが必要printf()です。C99 では、すべての関数のプロトタイプが必要です。C89 と C99 の両方でO_RDONLY、 、O_WRONLYSTDOUT_FILENOおよびのスコープで宣言が必要ですNULL
  2. -1の許可された戻り値ではありませんmain()
  3. C89 では、宣言とステートメントを混在させることはできません。

些細な問題: 通常の命名法は、「父と子」ではなく「親子」です。

この問題を修正し、読みやすさを改善するために、プログラムを修正しました。

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("An argument must be specified\n");
        return 1;
    }

    int ret = mkfifo("./fifo.txt", 0644);
    char buf;

    if (ret < 0) {
        perror("Error creating FIFO");
        return 1;
    }

    pid_t pid = fork();

    if (pid < 0) {
        perror("Error creating child process");
        return 1;
    }

    if (pid == 0) { /* child */
        int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */

        while(read(fd, &buf, 1) > 0) {
            write(STDOUT_FILENO, &buf, 1);
        }
        write(STDOUT_FILENO, "\n", 1);
        close(fd);
        return 0;
    } else { /* parent */
        int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */

        write(fd, argv[1], strlen(argv[1]));
        close(fd);
        waitpid(pid, NULL, 0);
        return 0;
    }
}

しかし、最も重要なのは、使用しているオペレーティング システムとコンパイラについて言及していないことです。

問題を再現できません。上記の問題のいずれかに関連している可能性があります。

于 2011-01-12T14:45:59.910 に答える