6

単純なシェルを構築するための割り当てに取り組んでおり、まだ必要とされていないいくつかの機能を追加しようとしていますが、パイプで問題が発生しています。

コマンドが解析されたら、それらを実行するプロセスをフォークします。このプロセスは、コマンドが1つだけ残っている場合はコマンドを実行するサブルーチンであり、それ以外の場合はフォークします。親は最初のコマンドを実行し、子は残りを処理します。パイプがセットアップされ、正しく機能します。

次に、メインプロセスがを呼び出しwait()、プロンプトを出力します。のようなコマンドを実行するとls -la | cat、catからの出力の前にプロンプ​​トが出力されます。

wait()実行する必要のあるコマンドごとに1回呼び出してみましたが、最初の呼び出しは機能し、後続のすべての呼び出しはに戻りECHILDます。

子の子を含むすべての子が終了するまでメインスレッドを強制的に待機させるにはどうすればよいですか?

4

3 に答える 3

7

できません。子プロセスに子を待機させ、すべての子が待機されるまで終了しないか、同じプロセスからすべての子をフォークします。

于 2012-10-10T15:13:24.553 に答える
4

この回答を参照してくださいwait()子プロセスの方法:fork()によって呼び出されるすべての子プロセスが完了するまで待つ方法は?

孫を待つ方法はありません。各プロセスに待機ロジックを実装する必要があります。そうすれば、各子は、すべての子が終了した後にのみ終了します(そして、それはすべての孫を反省的に含みます)。

于 2012-10-10T15:13:20.137 に答える
0

あなたは孫について話しているので、あなたは明らかに子をカスケード的にスポーンしています。これは、パイプを実装するための可能な方法です。

ただし、パイプからの戻り値(ターミナルで実行するときに取得する値echo $?)は、右端のコマンドから返される値であることに注意してください。

これは、このカスケード実装では、子を右から左にスポーンする必要があることを意味します。あなたはその戻り値を失いたくありません。

ここで、単純化のために組み込みコマンドについてのみ話していると仮定すると(fork()およびexecve()への追加の呼び出しは行われません)、興味深い事実は、「zsh」などの一部のシェルでは、右端のコマンドはそうではないということです。フォークさえ。次のような単純なパイプコマンドでそれを確認できます。

export stack=OVERFLOW | export overflow=STACK

次にコマンドを使用するenvと、環境変数でのoverflow=STACKの永続性を理解できます。これは、右端のコマンドがサブシェルで実行されなかったことを示していますが、実行されましたexport stack=OVERFLOW

注:これは、「sh」のようなシェルには当てはまりません。

次に、基本的なパイプコマンドを使用して、このカスケード実装の可能なロジックを示します。

cat /dev/random | head

注:これcat /dev/randomはおそらく終了しないコマンドですが、コマンドheadが。によって出力された最初の行の読み取りを完了するとすぐに停止しcat /dev/randomます。これは、実行時にstdinが閉じられ、壊れたパイプへの書き込みが原因headでコマンドが中止されるためです。cat /dev/random

論理:

  1. 親プロセス(シェル)は、実行するパイプがあることを確認します。次に、2つのプロセスをフォークします。親はシェルに留まり、子が戻るのを待ち、返された値を保存します。

  2. 第1世代の子のコンテキストでは、(パイプの右端のコマンドを実行しようとしています)コマンドが最後のコマンドではないことがわかり、再びfork()します(私が「カスケード実装」と呼んでいます)。フォークが完了したので、親プロセスは最初にそのタスク(head -1)を実行し、次にstdinとstdoutを閉じてから、子を待ちます()。これは、最初にstdinとstdoutを閉じてから、wait()を呼び出すことが非常に重要です。stdinで読み取る場合、stdoutを閉じると、EOFが親に送信されます。stdinを閉じると、パイプに書き込もうとしている孫が「壊れたパイプ」エラーで中止されることを確認します。

  3. 孫のコンテキストでは、パイプの最後のコマンドであることがわかり、コマンドを実行してその値を返します(stdinとstdoutを閉じます)。

于 2020-03-21T04:06:09.517 に答える