Dup2とForkを一緒に使用するにはどうすればよいですか?
質問
私はオペレーティングシステムコースを受講していますが、フォークがあるときに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にその出力を与える必要があるため、これは逆方向に考えられる必要があると考え続けています...しかし、子供と孫の両方が並行して処理されているため、それは意味をなさないようです。
解決
まず、コードを修正して、少しエラーチェックを少し追加し、機能するようにしましょう。ボトムビットを次のものに置き換えます。
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
標準入力から読み取りますdup
ed to0
.質問: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
「重要」とマークされたものを除く行を除く行wc
とps
動作するので、標準的なプラクティスは、完全に使用していないパイプの端を閉じて、1つの記述子のみで使用している端を開いたままにすることです。あなたが使用しているのでdup2
両方のプロセスで、それは4つを意味しますclose
上記のステートメント。
編集:引数を更新しました execlp
.