質問

私はオペレーティングシステムコースを受講していますが、フォークがあるときにDUP2で入力がリダイレクトされる方法に苦労しています。私はこの小さなプログラムを書いて、それのために感覚を得ようとしましたが、私は孫の出力を子供に渡すことに成功していませんでした。 Unixコマンドを模倣しようとしています:ps -a | WC -L。私はUNIXを初めて使用しますが、これは私が得る実行プロセスのリストの行を数えるべきだと思います。したがって、私の出力は単一の数字でなければなりません。

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>

using namespace std;

int main( int argc, char *argv[] )  {

    char *searchArg = argv[ 1 ];
    pid_t pid;

    if ( ( pid = fork() ) > 0 ) {
        wait( NULL );
        cout << "Inside parent" << endl;
    } 
    else if ( pid == 0 ) {
            int fd1[ 2 ];
            pipe( fd1 );
            cout << "Inside child" << endl;

            if ( pid = fork() > 0 ) {
                dup2( fd1[ 0 ], 0 );
                close( fd1[ 0 ] );
                execlp( "/bin/wc", "-l", NULL );
            }
            else if ( pid == 0 ) {
                cout << "Inside grand child" << endl;
                execlp( "/bin/ps", "-A", NULL );
            }
        }
    return 0;
}

上記のコードにはありませんが、物事がどのようにダウンすべきかについての私の推測は次のとおりです。

  • コマンドPS -Aの標準出力をリダイレクトする必要があります(通常、画面に印刷されるものは何でも正しいですか?)。WC-Lコマンドがそれを使用して行をカウントできるようにします。
  • この標準出力は、dup2(?、1)のようにdup2を使用してリダイレクトできます。これは、標準出力を?それからあなたは閉じますか?

質問:どこにリダイレクトしますか?私はそれがファイル記述子の1つであるべきであることを知っていますが、WCがそれを処理できるようにどこにリダイレクトすべきですか?

  • WCはどういうわけか標準出力を受け取ります。

質問:WCはどのように出力を受け取りますか? execlpパラメーターを介して?または、オペレーティングシステムはファイル記述子の1つをチェックしますか?

  • WC -Lを実行します。

これらのどれが閉じられており、WCがPSの出力を受け取って処理するために開いたままになっていますか? PSはWCにその出力を与える必要があるため、これは逆方向に考えられる必要があると考え続けています...しかし、子供と孫の両方が並行して処理されているため、それは意味をなさないようです。

pipe dream

役に立ちましたか?

解決

まず、コードを修正して、少しエラーチェックを少し追加し、機能するようにしましょう。ボトムビットを次のものに置き換えます。

else if ( pid == 0 ) {
        int fd1[ 2 ];
        pipe( fd1 );
        cout << "Inside child" << endl;

        if ( pid = fork() > 0 ) {
            if (dup2( fd1[ 0 ] , 0 ) < 0) {
              cerr << "Err dup2 in child" << endl;
            }
            close( fd1[ 0 ] );
            close( fd1[ 1 ] ); // important; see below
            // Note: /usr/bin, not /bin
            execlp( "/usr/bin/wc", "wc", "-l", NULL );
            cerr << "Err execing in child" << endl;
        }
        else if ( pid == 0 ) {
            cout << "Inside grand child" << endl;
            if (dup2( fd1[ 1 ] , 1 ) < 0) {
              cerr << "Err dup2 in gchild" << endl;
            }
            close( fd1[ 0 ] );
            close( fd1[ 1 ] );
            execlp( "/bin/ps", "ps", "-A", NULL );
            cerr << "Err execing in grandchild" << endl;
        }
}

さて、あなたの質問:

  • 質問:どこにリダイレクトしますか?私はそれがファイル記述子の1つであるべきであることを知っていますが、WCがそれを処理できるようにどこにリダイレクトすべきですか?

    提出された登録者 0, 1, 、 と 2 UNIXでは、標準の入力、標準出力、および標準誤差であるという点で特別です。 wc 標準入力から読み取ります duped to 0.

  • 質問:WCはどのように出力を受け取りますか? execlpパラメーターを介して?または、オペレーティングシステムはファイル記述子の1つをチェックしますか?

    一般的に、プロセスの後、その画像は exec, 、以前に持っていたすべての開いたファイル記述子があります exec. 。 (の記述子を除く CLOSE_ON_EXEC フラグが設定されていますが、今のところそれを無視してください)したがって、あなたが dup2 何か 0, 、 それから wc それを読みます。

  • これらのどれが閉じられており、WCがPSの出力を受け取って処理するために開いたままになっていますか?

    上記のように、子供と孫の両方でパイプの両端を閉じることができます。それは大丈夫でしょう。実際、標準的な実践では、それを行うことをお勧めします。しかし、本当に必要なのは唯一です close この特定の例の行は、私が「重要」とコメントするものです - それは 書きます 子供のパイプの端。

    アイデアはこれです。子供と孫の両方が、開始時にパイプの両端を開いています。今、スルー dup 接続しました wc パイプの読み取り端に。 wc パイプの書き込み端にあるすべての記述子が閉じられるまで、そのパイプを吸い続けます。その時点で、それがファイルの最後に来て停止することがわかります。さて、壮大な子供では、何も閉じないことで逃げることができます。 ps -A 記述子のいずれでも何もするつもりはありませんが、記述子に書き込みます 1, 、 以降 ps -A 終了するプロセスについて吐き出し、持っていたものすべてを閉じます。子供では、に保存されている読み取り記述子を閉じる必要はありません fd[0] なぜなら wc 記述子以外のものから読み込もうとはしません 0. 。ただし、子供のパイプの書き込み端を閉じる必要があります。 wc 完全に閉まっていないパイプでそこに座るだけです。

    ご覧のとおり、なぜ私たちが実際に必要としなかった理由の理由 close 「重要」とマークされたものを除く行を除く行 wcps 動作するので、標準的なプラクティスは、完全に使用していないパイプの端を閉じて、1つの記述子のみで使用している端を開いたままにすることです。あなたが使用しているので dup2 両方のプロセスで、それは4つを意味します close 上記のステートメント。

編集:引数を更新しました execlp.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top