0

パイプを使用する C コードを書いています。子プロセスが出力に STDOUT の代わりにパイプを使用するようにするには、次の行を使用しました。

    close(STDOUT);
    dup2(leftup[1], STDOUT);

ただし、ある種の無限ループに入るか、それらの行にハングアップするようです。を取り除くとclose、 ハングアップしdup2ます。

不思議なことに、STDIN の直前の行でも同じ考え方が機能します。

close(STDIN);
dup2(leftdown[0], STDIN);

この動作の原因は何ですか?

編集:明確にするために...

#define STDIN   0
#define STDOUT  1

編集 2: これは簡略化された例です。

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

#define STDIN   0
#define STDOUT  1

main(){
    pid_t child1 = 0;
    int leftdown[2];
    if (pipe(leftdown) != 0)
        printf("ERROR");
    int leftup[2];
    if (pipe(leftup) != 0)
        printf("ERROR");

    printf("MADE PIPES");

    child1 = fork();
    if (child1 == 0){
        close(STDOUT);
        printf("TEST 1");
        dup2(leftup[1], STDOUT);
        printf("TEST 2");
        exit(0);
    }
    return(0);  
}

"TEST 1"ラインに到達することはありません。唯一の出力は"MADE PIPES".

4

2 に答える 2

1

少なくともdup2関数が ではなく新しいファイル記述子を返すことを確認する必要があります-1

エラーが発生する可能性は常にあります (たとえば、pipe()呼び出しが以前に失敗した場合など)。さらに、正しいインデックス (0 と 1) を使用していることを絶対に確認してください。私は以前にそれに噛まれたことがあり、親プロセスにいるか子プロセスにいるかによって異なります。


あなたの編集に基づいて、私はそれMADE PIPESが最後に印刷されたことに少しも驚いていません.

を印刷しようとするとTEST 1、すでに記述子が閉じられているSTDOUTため、どこにも行きません。

印刷しようとすると、記述子TEST 2dup編集STDOUTされて親に送られますが、親はそれを読みません。

分岐コードを次のように変更した場合:

child1 = fork();
if (child1 == 0){
    int count;
    close(STDOUT);
    count = printf("TEST 1\n");
    dup2(leftup[1], STDOUT);
    printf("TEST 2 (%d)\n", count);
    exit(0);
} else {
    char buff[80];
    read (leftup[0], buff, 80);
    printf ("%s\n", buff);
    sleep (2);
}

TEST 2 (-1)パイプを介して読み取られるため、行が親によって出力されることがわかります。そこには、記述子を閉じた後 (ただし、編集する前) に子で試行した-1からの戻りコードがあり、失敗したことを意味します。printfSTDOUTdup

からISO C11 7.20.6.3 The printf function:

このprintf関数は、送信された文字数を返すか、出力エラーまたはエンコード エラーが発生した場合は負の値を返します。

于 2013-02-10T06:28:42.503 に答える
1

言及する複数のこと、

fork を使用すると、親プロセスのほぼ完全なコピーが作成されます。stdoutこれには、標準出力ストリーム用に設定されたバッファーも含まれます。ストリームは、stdoutバッファーがいっぱいになるか、バッファー/ストリームからデータをフラッシュするように明示的に要求されるまで、データを保持します。このため、"MADE PIPES"バッファに座っています。STDOUTfdを閉じprintfて端末にデータを書き込むために使用すると、"TEST 1"and"TEST 2"stdoutバッファーに転送されるだけで、エラーやクラッシュは発生しません (バッファーが十分にあるため)。したがって、出力がバッファリングされているため、pipefd onを複製した後でもSTDOUTprintfパイプの書き込み終了にも触れていません。最も重要なことは、API のセットを 1 つだけ使用してください。つまり、*NIX または標準の C ライブラリ関数のいずれかです。ライブラリはしばしばある種の最適化のためにトリックを実行するため、ライブラリをよく理解してください。

さて、言及する別のことは、適切なプロセスでパイプの適切な端を閉じていることを確認してください. つまり、親から子への通信に pipe-1 が使用されている場合は、親で読み取り側を閉じ、子で書き込み側を閉じていることを確認してください。そうしないと、ファイル記述子に関連付けられた参照カウントのために、プログラムがハングする可能性があります。ただし、親で読み取り終了を閉じない場合と同様に、パイプの読み取り終了に余分な参照カウントがあり、最終的にパイプは閉じられません。

あなたのコーディング スタイルには他にも多くのことがあります。:)

エラー チェックは絶対に重要です。少なくとも assert を使用して、仮定が正しいことを確認してください。

ステートメントを使用printfしてエラーをログに記録したり、デバッグの方法としてターミナル FD を変更したりする場合は、(STDOUT / STDIN / STDERR)open でログ ファイルを*NIX開き、エラー/ログ エントリを書き込みます。

最後に、straceutility を使用すると非常に役立ちます。このユーティリティを使用すると、コードの実行中に実行されたシステム コールを追跡できます。それは非常に単純明快です。適切な権限があれば、これを実行中のプロセスにアタッチすることもできます。

于 2013-02-10T10:41:43.103 に答える