2015-10-30 22 views
5

誰かが、親プロセスがいつでも完全に終了する理由を説明することができます。親が終了するまでの子供のための同じ、親プロセスでsleep()を使用しても、子プロセスが最後に実行されます。

Parent: .. 
Parent: .. 
Parent: .. 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 

int main(int argc, char **argv) { 
    int i = 10000, pid = fork(); 
    if (pid == 0) { 
     while(i > 50) { 
      if(i%100==0) { 
       sleep(20); 
      } 
      printf("Child: %d\n", i); 
      i--; 
     } 
    } else { 
     while(i < 15000) { 
      if(i%50==0) { 
       sleep(50); 
      } 
      printf("Parent: %d\n", i); 
      i++; 
     } 
    } 
    exit(EXIT_SUCCESS); 
} 

出力は次のようになります。

なぜ私は単一のコアCPUでテストしているのでしょうか?マルチコアの設定をしても結果は変わりますか?スリープ(50)は間違いなく機能しています。スクリプトが終了するまでに時間がかかります。なぜCPUがプロセスを切り替えないのですか?プロセスがCPUに対する「より多くの」排他的な権利を持っているwhileループのような状況がありますか?

ありがとうございました。 :)

+0

どのような睡眠(50)? –

+0

誰かがコードをコピー/ペーストしたい場合、sleep(50)をsleep(30)に変更しました。睡眠(50)は私のために長い時間がかかります。私は2番目にそれを編集しています。 – chh

答えて

3

CPUに「もっと」または排他的な権利があるwhileループのような状況がありますか?

まあ、それは定義されていませんが、それは気違いです。

問題を再現できません。睡眠時間を25秒に減らす(私は永遠に待つ必要がないので)子供は、最初にブロックされなくなります。 (AMD64のDebian 8、Linux 3.16.1-ck1 [BFSスケジューラ、非標準]

あなたのスケジューラは非常に変わった動作をしており、になるかもしれません。しかし、それはスケジューラの特定の動作に依存することは決して良い考えではないと言われています。常にそれは地獄のように破壊され、非常識だと仮定し - 。あなたのコードが実行の特定の順序を許可する場合、あり、したがって

(*)それを選択するのに十分な非常識なスケジューラも同期プリミティブ(semaphoresmutexesのために使用します。たとえば、共有のバージョンで、異なるプロセスで使用することができます - いくつかのシナリオではpipesを使用することもできます)。

edit:プロセスを同期させるための2つの例を追加します。

最初のバージョン(AB)を用いpipe S:そして

#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 

int main(int argc, char **argv) { 
    int i = 10000; 
    int parent_done[2]; 
    int child_done[2]; 
    char dummy[1] = { 0 }; 
    int pid; 

    pipe(parent_done); 
    pipe(child_done); 

    /* stdio buffering would lead to intermingled output */ 
    setvbuf(stdout, 0, _IONBF, 0); 

    pid = fork(); 

    if (pid == 0) { 
     close(parent_done[1]); 
     close(child_done[0]); 

     while(i > 50) { 
      if(i%100==0) { 
       if (i < 10000) write(child_done[1], dummy, 1); 
       read(parent_done[0], dummy, 1); 
      } 
      printf("Child: %d\n", i); 
      i--; 
     } 
    } else { 
     close(parent_done[0]); 
     close(child_done[1]); 

     while(i < 15000) { 
      if(i%50==0) { 
       write(parent_done[1], dummy, 1); 
       read(child_done[0], dummy, 1); 
      } 
      printf("Parent: %d\n", i); 
      i++; 
     } 
    } 
    exit(EXIT_SUCCESS); 
} 

同じ用いPOSIXセマフォ(セマフォがを意味するので、私見はるかにクリーンであり、同期のために使用される):

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/mman.h> 
#include <semaphore.h> 
#include <unistd.h> 

struct semaphores 
{ 
    sem_t child_done; 
    sem_t parent_done; 
}; 

int main(int argc, char **argv) { 
    int i = 10000; 
    int pid; 

    /* map shared memory for the semaphores */ 
    struct semaphores *sems = mmap(0, sizeof(*sems), PROT_READ|PROT_WRITE, 
      MAP_SHARED|MAP_ANONYMOUS, -1, 0); 

    /* initialize both semaphores as "shared" and with an initial count 
    * of 0 */ 
    sem_init(&sems->parent_done, 1, 0); 
    sem_init(&sems->child_done, 1, 0); 

    /* stdio buffering would lead to intermingled output */ 
    setvbuf(stdout, 0, _IONBF, 0); 

    pid = fork(); 

    if (pid == 0) { 
     while(i > 50) { 
      if(i%100==0) { 
       if (i < 10000) sem_post(&sems->child_done); 
       sem_wait(&sems->parent_done); 
      } 
      printf("Child: %d\n", i); 
      i--; 
     } 
     sem_post(&sems->child_done); 
    } else { 
     while(i < 15000) { 
      if(i%50==0) { 
       sem_post(&sems->parent_done); 
       sem_wait(&sems->child_done); 
      } 
      printf("Parent: %d\n", i); 
      i++; 
     } 
     sem_post(&sems->parent_done); 
    } 
    exit(EXIT_SUCCESS); 
} 

WindowsはセマフォーのAPIが異なります。Semaphore Objects on MSDN

(*) edit2ここにあてはまる:例を作成しているうちに、私はstdioが眠らずに途中でバッファリングをしていることに気づいた。だからあなたのスケジューラでさえ悪く振る舞いませんが、stdioの実装では非常にの予期せぬ動作ので、のバッファをフラッシュします。それは当然の野生の推測です。すべてのFILEハンドルは、Cライブラリのstdio部分によってバッファされます。これには、あらかじめ定義されたstdin,stdoutおよびstderrのハンドルが含まれます。結果として、出力で表示される内容が、異なるスレッドまたはプロセスがその出力を作成した順序を必ずしも反映しているとは限りません。私の例のスニペットのように完全にバッファリングを無効にしない限り、もちろんです。

+1

@chh私はいくつかのサンプルコードを追加しましたが、Windows用ではあまりにも怠惰でした(パイプを使ったバージョンが動作するかもしれませんが、 'msvcrt'が標準の' pipe() '呼び出しを提供しているかどうかはまだ分かりません)。 –

+1

@あなたが最初に経験した反直観的な行動の別の原因を追加しました。 –

+0

これはまさに私が探していたものです。時間をとっていただきありがとうございます。 – chh

関連する問題