1

検討:

int main()
{
        if (fork() == 0){
            printf("a");
        }
        else{
            printf("b");
            waitpid(-1, NULL, 0);
        }
        printf("c");
        exit(0);
 }

(Computer Systems、Bryant - O'Hallaron から)。

可能なすべての出力シーケンスを求められます。

私は答えました:acbc、abcc、bacc。ただし、ソリューション (bcac) と比較して 1 つの出力がありません。親プロセスは c (waitpid) を出力する前に子プロセスが戻るのを待っているため、この出力は不可能だと思いました。これは真実ではありませんか?なんで?そして、その場合、上記のコードと waitpid 行のない同じコードの違いは何ですか?

4

2 に答える 2

3

どんな方法も可能だとは思いませんbcac。最初は、stdio バッファーが予期しない順序でフラッシュされることに基づいて、いくつかの策略を期待していました。しかし、それでも:

子は outputcになるまで出力しませんa。したがって、最初のcインbcacは親からのものでなければなりません。

親は、が完了cするまで出力しません。waitpidしかし、これは、 の間に発生する最後の stdio フラッシュを含め、子が終了するまで発生しませんexit()。したがって、最初cは常に子供からです。

矛盾による証明が達成されました...出力は ではありませんbcac

さて、順序を台無しにするためにできることが 1 つあります。終了しようとしている子が既にあるプロセス内でプログラムを実行できます。新しい子が を出力する前に既存の子が終了した場合a、メイン プロセスはでその終了を検出しwaitpid、先に進んでその内容を出力し、場合によっては子が何かを出力する前に終了します。

これは、setuid プログラムで注意すべきことです。プログラムが子プロセスを 1 つだけ作成したからといって、子プロセス1 つしかないと思い込まないでください。高度な防御コード学習のコンテキストにいる場合、この答えは理にかなっています。Unix初心者のコンテキストでは、それは関連性がないように思われbcacます。技術的には真実ではありませんが、不可能であると言う方がおそらく良いでしょう.

于 2014-08-13T02:09:23.290 に答える
1

トリッキーですが、 への呼び出しwaitpidが中断される可能性があります (戻り値-1と errno は ですEINTR)。この場合、親cは子が何かを出力する前に出力でき、bcac可能です。

発生を防ぐbcacには、シグナルマスクを設定するか、waitpid戻り値をチェックして、中断された場合は再度呼び出されるようにする必要があります。

于 2014-08-13T06:38:57.780 に答える