web-dev-qa-db-ja.com

簡単な例でCのfork()を理解する

#include <stdio.h>
int num = 0;
int main(int argc, char*argv[]){
    int pid;
    pid = fork();
    printf("%d", num);  
    if(pid == 0){       /*child*/
        num = 1;
    }else if(pid > 0){  /*parent*/
        num = 2;
    }
    printf("%d", num);
}

可能な出力が0102または0012または0201または0021になる理由を理解するのに問題があります。

これが私が(考えて)作成すべきものです。これは最初のprintfステートメントにヒットし、どの子または親が最初に実行されても、numは変更されていないため、最初に0になります。次に、nextは1または2のいずれかであり、次のプロセスが実行されるため、(親からコピーされた)0から始まり、1または2のいずれかが再び実行されます。したがって、可能な出力は次のようになります。

0101または0102または0201または0202

9
Locke McDonnell

親と子の両方で、最初のprintfのnumは0です。親と子の両方で、0が出力され、その後に他の値が続きます。親プロセスでは、他の値は2です。子プロセスでは、他の値は1です。

ただし、注意すべき重要な点は、各プロセスには、他の番号の前にゼロを印刷する必要があるという強制的な順序がありますが、2つのプロセスの相互の印刷に制限はないということです。

これが実際の例えです。同僚と私が同時に仕事を辞め、食料品店に立ち寄ってから家に帰るとします。私は家に帰る前に店にいたこと、そして彼が家に帰る前に食料品店にいたことを知っています。しかし、誰が最初に食料品店にいたのか、誰が最初に家にいたのかはわかりません。私たちはそれぞれ同じ時間に食料品店に到着し、次に同じ時間に家に到着する可能性があります。あるいは、彼が遅れて、彼が店に着く前に食料品店と家に着くかもしれません。

起こらないことは、1つまたは2つを複数回印刷することです。 forkが戻った後、概念的に同時に2つのプロセスが実行され、それらのイベントの相対的なタイミングは指定されていませんが、各プロセスのイベントの順序は明確に定義されています。各プロセスは、numを1または2に設定してから再度出力します。また、forkは、子で0を返し、親で子のpidを返すように定義されているため、それぞれ次のように設定します。異なる値。

実際には、別の妥当な出力があります:00forkが新しいプロセスを作成できない場合、-1を返します。この場合、プログラムは0を出力し、ifelse ifsは失敗します。-1が0でも0より大きくなく、numが変更されないため、プログラムは0を再度出力します。

Cプログラムでの効果の順序の定義について多くを学びたい場合、検索するキーワードは「シーケンスポイント」です。このプログラムでは、(2つのコピーを同時に実行しているという事実を除けば)かなり簡単ですが、わかりにくい場合もあります。

10

これはfork()の問題ではありません。 printf()がバッファリングされるため、これはprintf()です。通常、バッファは最後に改行文字 '\ n'が見つかったときにフラッシュされます。ただし、これを省略したため、バッファの内容は保持され、フラッシュされません。最終的に、両方のプロセス(元のプロセスと子)には、0または1の出力バッファーが含まれます。最終的にフラッシュされると、両方のプロセスでこれが表示されます。

fflush(stdout);の後にprintf()を追加して試してください。

9
user2166576