2015-01-30 3 views
3

У меня есть вопрос о следующем коде. Это пример, найденный на this page, а не мой код.вызовы fork() и wait()

Родительский процесс выдает 2 дочерних процесса, каждый из которых составляет 200, а затем выходит. Я не понимаю, почему дети не печатают свои сообщения сразу после того, как они разветвлены, и они позволяют своему отцу войти в состояние ожидания? Также, как вызов системы ожидания возвращает pid ребенка, который заканчивается первым?

pid = wait (& status);

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

#define MAX_COUNT 200 
#define BUF_SIZE 100 

void ChildProcess(char [], char []); /* child process prototype */ 

void main(void) 
{ 
    pid_t pid1, pid2, pid; 
    int  status; 
    int  i; 
    char buf[BUF_SIZE]; 

    printf("*** Parent is about to fork process 1 ***\n"); 
    if ((pid1 = fork()) < 0) { 
      printf("Failed to fork process 1\n"); 
      exit(1); 
    } 
    else if (pid1 == 0) 
      ChildProcess("First", " "); 

    printf("*** Parent is about to fork process 2 ***\n"); 
    if ((pid2 = fork()) < 0) { 
      printf("Failed to fork process 2\n"); 
      exit(1); 
    } 
    else if (pid2 == 0) 
      ChildProcess("Second", "  "); 

    sprintf(buf, "*** Parent enters waiting status .....\n"); 
    write(1, buf, strlen(buf)); 
    pid = wait(&status); 
    sprintf(buf, "*** Parent detects process %d was done ***\n", pid); 
    write(1, buf, strlen(buf)); 
    pid = wait(&status); 
    printf("*** Parent detects process %d is done ***\n", pid); 
    printf("*** Parent exits ***\n"); 
    exit(0); 
} 

void ChildProcess(char *number, char *space) 
{ 
    pid_t pid; 
    int i; 
    char buf[BUF_SIZE]; 

    pid = getpid(); 
    sprintf(buf, "%s%s child process starts (pid = %d)\n", 
      space, number, pid); 
    write(1, buf, strlen(buf)); 
    for (i = 1; i <= MAX_COUNT; i++) { 
      sprintf(buf, "%s%s child's output, value = %d\n", space, number, i); 
      write(1, buf, strlen(buf)); 
    } 
    sprintf(buf, "%s%s child (pid = %d) is about to exit\n", 
      space, number, pid); 
    write(1, buf, strlen(buf));  
    exit(0); 
} 

Выход для MAX_COUNT 40.

*** Parent is about to fork process 1 *** 
*** Parent is about to fork process 2 *** 
*** Parent enters waiting status ..... 
    First child process starts (pid = 3300) 
    First child's output, value = 1 
     Second child process starts (pid = 3301) 
     Second child's output, value = 1 
    First child's output, value = 2 
     Second child's output, value = 2 
     Second child's output, value = 3 
    First child's output, value = 3 
     Second child's output, value = 4 
    First child's output, value = 4 
     Second child's output, value = 5 
    First child's output, value = 5 
     Second child's output, value = 6 
    First child's output, value = 6 
     Second child's output, value = 7 
    First child's output, value = 7 
     Second child's output, value = 8 
    First child's output, value = 8 
     Second child's output, value = 9 
    First child's output, value = 9 
     Second child's output, value = 10 
    First child's output, value = 10 
     Second child's output, value = 11 
    First child's output, value = 11 
     Second child's output, value = 12 
    First child's output, value = 12 
     Second child's output, value = 13 
    First child's output, value = 13 
     Second child's output, value = 14 
    First child's output, value = 14 
     Second child's output, value = 15 
    First child's output, value = 15 
     Second child's output, value = 16 
    First child's output, value = 16 
     Second child's output, value = 17 
    First child's output, value = 17 
     Second child's output, value = 18 
    First child's output, value = 18 
     Second child's output, value = 19 
    First child's output, value = 19 
     Second child's output, value = 20 
    First child's output, value = 20 
     Second child's output, value = 21 
    First child's output, value = 21 
     Second child's output, value = 22 
    First child's output, value = 22 
     Second child's output, value = 23 
    First child's output, value = 23 
     Second child's output, value = 24 
    First child's output, value = 24 
     Second child's output, value = 25 
    First child's output, value = 25 
     Second child's output, value = 26 
    First child's output, value = 26 
     Second child's output, value = 27 
    First child's output, value = 27 
     Second child's output, value = 28 
    First child's output, value = 28 
     Second child's output, value = 29 
    First child's output, value = 29 
     Second child's output, value = 30 
    First child's output, value = 30 
     Second child's output, value = 31 
    First child's output, value = 31 
     Second child's output, value = 32 
    First child's output, value = 32 
     Second child's output, value = 33 
    First child's output, value = 33 
     Second child's output, value = 34 
    First child's output, value = 34 
     Second child's output, value = 35 
    First child's output, value = 35 
     Second child's output, value = 36 
    First child's output, value = 36 
     Second child's output, value = 37 
    First child's output, value = 37 
     Second child's output, value = 38 
    First child's output, value = 38 
     Second child's output, value = 39 
    First child's output, value = 39 
     Second child's output, value = 40 
    First child's output, value = 40 
     Second child (pid = 3301) is about to exit 
    First child (pid = 3300) is about to exit 
*** Parent detects process 3300 was done *** 
*** Parent detects process 3301 is done *** 
*** Parent exits *** 

Почему *** Parent enters waiting status ..... линия отображается в начале, а не где-то после того, как Чайлдс начать печать?

+0

Что вы подразумеваете под «почему дети не печатают свои сообщения сразу после того, как они разветвлены, и они позволяют своему отцу войти в состояние ожидания?» в точку. Не совсем ясно, каков ваш вопрос сейчас. –

+0

Знаете ли вы, что 'fork()' создает новые процессы (без разрушения первого) и что несколько процессов могут выполняться одновременно? Если так, я не уверен, что вы просите. – Dmitri

+0

@ ian-sellar @dmitri 'fork()' создает другой процесс, который в нашем случае, потому что он является дочерним, вводит 'ChildProcess (« First »,« »);'. Прямо сейчас, почему он не печатает от 1 до 200? Почему сообщение «*** Родитель входит в состояние ожидания .....» не отображается где-то между 1-200 или в конце? – Shury

ответ

2

Вилка выполняет новый процесс, который может выполняться одновременно (или чередуется) с родительским процессом. Это не приводит к остановке родительского процесса. После вызова fork оба процесса выполняются «runnable», и вполне возможно, что оба они запущены. Если родительский процесс повезет, он будет первым, который сможет выводить. В общем, это непредсказуемо.

В этом коде есть ряд ошибок, поэтому я бы не рассматривал его как хороший источник обучения использованию fork().

Например, родительский процесс использует printf для записи сообщения:

*** Parent is about to fork process 1 *** 
*** Parent is about to fork process 2 *** 

Тем не менее, вполне возможно, что stdout является не линия буфера (например, это может быть перенаправлено.) В в этом случае вывод будет только скопирован в буфер вывода в памяти и будет напечатан до stdout, когда буфер заполняется, или дескриптор файла stdout закрыт. Тем не менее, дети будут разветвляться с тем же буфером вывода в памяти, поэтому как родительский, так и дочерний будут выдавать сообщение *** Parent is about to fork process 1 ***, и все три процесса выдадут сообщение *** Parent is about to fork process 2 ***.

Кроме того, если stdout перенаправлен на поисковый поток, не открытый в режиме добавления, то дескриптор файла 1 каждого процесса будет иметь связанную с ним позицию файла, каждая из которых будет работать независимо. Это может привести к тому, что два дочерних процесса будут перезаписывать друг друга. (В моей системе перезапись происходит примерно в 80% случаев.)

+0

Как точка отсчета. На более раннем двухъядерном процессоре x86_64 w/openSuSE первый дочерний процесс (fcp) запускает и выводит 1-9, прежде чем родитель входит в ожидании. fcp продолжает последовательно выводить 10-200. fcp собирается выйти, а второй дочерний процесс (scp) начинается с последовательного вывода 1-174, где родитель обнаруживает fcp. scp продолжается последовательно 175-200. Я подозреваю, что это полностью процессор/планировщик/загрузка, зависящая от каждой машины. –

+0

@ DavidC.Rankin: полностью. Не говоря уже о фазе Луны. «В общем, это непредсказуемо». – rici

0

В незанятой многоядерной или многопроцессорной системе очень вероятно, что дети начали выполнять почти мгновенно. В Unix и Linux forking - это быстрая и простая операция: скопируйте некоторые дескрипторы памяти, дублируйте некоторые ресурсы, исправьте некоторую сигнальную логику и оставьте оба процесса работоспособными. Планировщик не предсказуем (на этом уровне наблюдения): он рассчитан на справедливость и справедливость.

Кроме того, что дети делают вычислительно более тяжелый — форматирование текста, буферным его в CRTL, возможно, перенося его на I/O систему — чем то, что делает родитель: вилка(), сравните число, ждать ().

Так что неудивительно, что родитель быстро добирается до своего ожидания(), в этот момент он больше не конкурирует за процессорное время.

После каждого printf() с fflush(stdout) может (или нет) улучшить согласованность, удалив два уровня буферизации ввода-вывода из микса.

+0

Код у детей не печатает f; это sprintf() s, а затем write() s. Цель состоит в том, чтобы избежать смежных проблем вывода и буферизации, но на самом деле это не решает проблему, как я объяснил в своем ответе. Во всяком случае, промывка или буферизация строк были бы хорошей идеей, но она применима только к нескольким строкам, напечатанным родителем. И первое, что сделано родителем и дочерним, примерно одинаково: форматируйте текст в буфер и затем вызывайте запись в этом буфере (который не выполняет дополнительную буферизацию в пользовательской области), поэтому производство первой выходной строки должно быть конкурентоспособным. – rici

Смежные вопросы