1

うまくいけば、簡単な質問です。fork()、pipe()、waitpid() を同時に学習しようとしていて、いくつかの問題が発生しています。

if (pipe(myout)<0 || pipe(myin)<0 || pipe(myerr)<0) { perror("Couldn't make pipes"); return; }
int childpid=fork();
if (childpid==0) { //child
    fdopen(myout[1], "w");
    fdopen(myin[1], "r");
    fdopen(myerr[1], "w");
    dup2(myout[1],  1);
    dup2(myin[1], 0);
    dup2(myerr[1], 2);
    printf("This should be seen\n");
    fclose(stdout); fclose(stdin); fclose(stderr);
    sleep(10);
    _exit(0);
 } else { //parent, wait on child
    printf("parent, monitoring\n");
    sim_out=fdopen(myout[0], "r");
    sim_in=fdopen(myin[0], "w");
    sim_err=fdopen(myerr[0], "r");
    printf("have my fds\n");
    int status;
    do {
        int ch;
        if (read(myout[0], &ch, 1)>0)
            write(1, &ch, 1);
        else printf("no go\n");
            waitpid(childpid, &status, WNOHANG);
    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
}

私は得ています:

親、監視には私の fds T があります

プログラムが終了する前 - つまり、ループは 1 回だけ実行されます。その下にチェックがあり、WIFEXITED() が近づいているので、プロセスは正常に終了したはずです。しかし、私が気になるのは、それが起こる前に sleep(10) があり、これがすぐに起こることです-子プロセスが残りの待機時間の間実行されたままであることは言うまでもありません.

私は根本的に何かを誤解しています、明らかに。私の期待は、親ループが子からの文字を確認するまでブロックし、それを読み取り、それがまだ生きているかどうかを確認することでした. 私は確かに、子供がまだ生きているときに waitpid() が WIFEXITED を設定するとは思っていませんでした。

どこが間違っていますか?

4

2 に答える 2

5

私はいくつかの問題を見ることができると思います。出現順に言及しようと思います。

  • エラーを示すfork戻り値を確認する必要があります(この場合、子はフォークされません)。-1
  • リソースリークへのすべての呼び出しfdopen(実装によって異なります。RHEL4リークへの呼び出し)。FILE*それらはあなたがそれから等で使用することができるそしてそれからそれらfwriteで行うことによって閉じることができるaを返しfcloseます。しかし、あなたはその価値を捨てます。読み取り/書き込みのためにパイプを開く必要はありません。パイプは、作成時にそれに適しています。
  • 子供は使用しないパイプの端を閉じる必要があります。追加close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
  • 私が知っているすべてのdup2Linuxバリアントで技術的には問題ありませんが、パイプの最初のfdを読み取りに使用し、もう1つを書き込みに使用するのが通例です。したがって、あなたdup2のsはに最もよく変更されますdup2 (myin [0], STDIN_FILENO); dup2 (myout [1], STDOUT_FILENO); dup2 (myerr [1], STDERR_FILENO);
  • 親は、使用しないパイプの端を閉じる必要があります。追加close (myin [0]); myin [0] = -1; close (myout [1]); myout [1] = -1; close (myerr [1]); myerr [1] = -1;
  • あなたの主な問題:statusあなたはあなたの子供の終了コードのためにおそらく初期化されていないことをチェックします。しかしwaitpid、まだ呼ばれていません。waitpidの終了コードを確認し、それが。status以外のものを返すかどうかを評価しないでくださいchildpid

編集

現在、実際に必要なパイプの端だけが開いているため、オペレーティングシステムが壊れたパイプを検出します。子供がそうするとパイプが壊れfclose (stdout)ます。親は引き続きパイプ内にある可能性のあるすべてのデータの読み取りに進むことができますが、その後readはゼロを返し、パイプが壊れていることを示します。

したがって、実際にはへの呼び出しを省くことができますwaitpidread代わりに、単にゼロが返されるのを待つことができます。ただし、これは100%同等ではありません。これは、子供がパイプに行く前にパイプの端を閉じるためsleep(すべてのデータが読み取られたときに親が続行するため)、waitpidもちろん、バージョンは子供が実際に死亡したときにのみ続行します。

于 2010-12-03T17:42:31.697 に答える
0

誰かがこれに答えました...私はそれに何が起こったのかわかりません。私がここの初心者であることを考えると、多分私はそれをどうにかして削除しましたか?もしそうなら、私は謝罪します、しかし彼らは答えを持っていました。

解決策は、waitpid()> 0でない限り、WIF *マクロを使用しないことです。そうでない場合は、明らかに0が通常の終了と見なされるためです。コードにチェックを挿入すると、機能するようになりました。ポインタを編集してくれた皆さんに感謝します。

于 2010-12-03T17:51:21.453 に答える