2015-08-08 3 views
0

Я изучаю межпроцессное общение и натолкнулся на приведенную ниже примерную программу.Вилка и трубы: эта программа C содержит условие гонки?

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

Что (если что-либо) ограничивает родительский процесс от попытки чтения со стандартного ввода до того, как дочерний процесс записал на стандартный вывод?

int main(void) 
{ 
    int  fd[2], nbytes; 
    pid_t childpid; 
    char string[] = "Hello, world!\n"; 
    char readbuffer[80]; 

    pipe(fd); 

    if((childpid = fork()) == -1) 
    { 
      perror("fork"); 
      exit(1); 
    } 

    if(childpid == 0) 
    { 
      /* Child process closes up input side of pipe */ 
      close(fd[0]); 

      /* Send "string" through the output side of pipe */ 
      write(fd[1], string, (strlen(string)+1)); 
      exit(0); 
    } 
    else 
    { 
      /* Parent process closes up output side of pipe */ 
      close(fd[1]); 

      /* Read in a string from the pipe */ 
      nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); 
      printf("Received string: %s", readbuffer); 
    } 

    return(0); 
} 
+0

при вызове системной функции 'pipe()', всегда проверяйте возвращаемое значение, чтобы убедиться, что операция прошла успешно. on success, pipe() возвращает 0 при неудаче, pipe() возвращает -1 и устанавливает «errno» – user3629249

+0

комментарии о закрытии концов конвейера обращаются назад – user3629249

+0

Функция 'read()' не добавляет байта окончания строки ' \ 0 'в строку чтения, поэтому немедленный вызов printf() (вероятно) завершится с ошибкой. В зависимости от того, что происходит первым, read() или write(), чтение может вернуться, не прочитав все байты данных. Чтение должно быть в цикле, проверяя/накапливая возвращаемые байты. Когда возвращаемый счетчик байтов равен 0, завершите строку, используя накопленные байтовые подсчеты (возможно, не обязательно, поскольку дочерний элемент отправляет байт завершения, но это хорошая практика). Если возвращаемое значение когда-либо <0 обрабатывает ошибку – user3629249

ответ

1

Ничто не мешает родителю запуска read() вызова до того, как ребенок написал ничего к трубе, но родительский процесс не получит каких-либо данных, пока после того, как ребенок записывает данные на трубе (и записи будет атомарным, потому что он меньше длины буфера канала). Родитель будет ждать, пока либо некоторые данные поступят на трубу, либо на каждый конец письма, который должен быть закрыт.

Обратите внимание, что после nbytes == 0 после считывания вывод printf() является неопределенным, поскольку readbuffer не инициализирован.

+0

Спасибо - это приводит меня к другому вопросу, который, вероятно, связан с другим недоразумением с моей стороны, но я все равно спрошу - как знает родитель, когда больше нет данных, поступающих в буфер буфера? Я думаю о сценарии, когда родитель запускает чтение, а потом потом записывает «H» «Hello, world!». - что мешает родителям принять сразу же после того, как он прочитал «H», что читать нечего? – sav0h

+0

Процесс чтения возвращает 0 байтов, когда больше нет данных для чтения, и нет процесса, который мог бы записать больше данных (так что все концы записи канала закрыты). Ядро обрабатывает это; процесс чтения должен только обратить внимание на значение, возвращаемое функцией 'read()'. –

+0

@ sav0h Пока один или несколько процессов имеют канал записи канала, процесс чтения (в вашем коде, родительском) всегда будет предполагать, что есть что-то еще для чтения (и будет блокировать в 'read (2)' if в данный момент нет ничего доступного). Обратите внимание, что * Hello, world! * Меньше, чем 'PIPE_BUF', поэтому запись является атомарной (см.' Man 7 pipe'); предполагая, что буфер, переданный в 'read (2)', достаточно длинный, достаточно одного 'read (2)' call. –

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