7

私はオペレーティング システムのコースを受講していますが、フォークがある場合に dup2 で入力をリダイレクトする方法に苦労しています。この小さなプログラムを書いて感覚をつかもうとしましたが、孫の出力を子に渡すことに成功しませんでした。unix コマンドを模倣しようとしています: ps -A | トイレ -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 に渡す必要があるため、これは逆に考える必要があると考え続けています...しかし、子と孫の両方が並行して処理されているため、それは意味がないようです。

夢物語

4

1 に答える 1

4

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

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が処理できるようにどこにリダイレクトする必要がありますか?

    ファイル記述子01、および2は、Unix では標準入力、標準出力、および標準エラーであるという点で特別です。wcは標準入力から読み取るため、dup編集されたものは何でも0.

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

    一般に、プロセスのイメージが でスワップ アウトされるとexec、プロセスは以前に開いていたすべてのファイル記述子を保持しますexec。(フラグが設定された記述子を除きCLOSE_ON_EXECますが、今は無視してください) したがって、dup2何かする場合は0、 thenwcがそれを読み取ります。

  • wc が ps の出力を受け取って処理するために閉じられ、開いたままになっているのはどれですか?

    上記のように、子と孫の両方でパイプの両端を閉じることができ、それで問題ありません。実際、標準的な慣行では、そうすることをお勧めします。ただし、closeこの特定の例で本当に必要な行は、「重要」とコメントした行だけです。これは、子のパイプの書き込み側を閉じています。

    アイデアは次のとおりです。子と孫の両方が、開始時にパイプの両端が開いています。これで、パイプの読み取り側にdup接続しました。パイプの書き込み側のすべての記述子が閉じられるまで、そのパイプを吸い続けます。閉じられた時点で、ファイルの最後に到達して停止することがわかります。さて、孫では、記述子のいずれかで何もせずに記述子に書き込むため、何も閉じずに逃げることができます。いくつかのプロセスに関するものを吐き出し終わった後、終了し、すべてを閉じますありました。子では、ディスクリプタ以外から読み取ろうとしないため、格納されている読み取りディスクリプタを閉じる必要はありません。wcwcps -A1ps -Afd[0]wc0. ただし、子のパイプの書き込み側を閉じる必要があります。そうしないwcと、パイプが完全に閉じられることはありません。

    ご覧のとおり、「重要」とマークされた行以外の行が本当に必要ない理由は、とがcloseどのように動作するかの詳細に依存するため、標準的な方法はパイプの端を閉じることです。完全には使用しておらず、使用している端を 1 つの記述子だけで開いたままにしてください。両方のプロセスで使用しているため、上記の 4 つのステートメントを意味します。wcpsdup2close

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

于 2012-01-14T09:01:27.790 に答える