2015-09-24 2 views
1

Следующий код является реализация труб приведены в руководстве Beej по:Beej направляющая труба Пример Объяснение

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(void) 
{ 
int pfds[2]; 
pipe(pfds); 
if (!fork()) { 
close(1); /* close normal stdout */ 
dup(pfds[1]); /* make stdout same as pfds[1] */ 
close(pfds[0]); /* we don't need this */ 
execlp("ls", "ls", NULL); 
} else { 
close(0); /* close normal stdin */ 
dup(pfds[0]); /* make stdin same as pfds[0] */ 
close(pfds[1]); /* we don't need this */ 
execlp("wc", "wc", "-l", NULL); 
} 
return 0; 
} 

Я хотел спросить:

  1. Возможно ли, что close(0) выполняется перед dup(pfds[1])? Если да, то в этом случае программа будет вести себя не так, как ожидалось.
  2. Что является использование следующих строк кода:

    close(pfds[0]); /* we don't need this */ 
    close(pfds[1]); /* we don't need this */ 
    

А что бы изменилось, если эти линии не были там?

ответ

1

Возможно ли, что close (0) выполняется до dup (pfds [1])? Если да, , тогда в этом случае программа не будет вести себя так, как ожидалось.

Да, это возможно, чтобы иметь родителя успешно завершить close(0) перед ребенком вызывает dup(pfds[1]). Однако это не проблема. Когда вы переделываете новый процесс, новый процесс получает всю копию адресного пространства памяти родителя, включая дескрипторы открытых файлов (кроме тех, которые отмечены флагом O_CLOEXEC - см. fcntl(2)). Таким образом, по существу, каждый процесс имеет свою личную копию дескрипторов файлов и изолирован и свободен делать все, что захочет, с этой копией.

Таким образом, когда родительский звонит close(0), он закрывает только свою копию дескриптора файла 0 (stdin); он никак не влияет на ребенка, который все еще имеет ссылку на stdin и может использовать его при необходимости (хотя в этом примере он не будет).

Что является использование следующих строк кода:

close(pfds[0]); /* we don't need this */ 
close(pfds[1]); /* we don't need this */ 

Лучшие практики мандат, который вы должны закрыть дескрипторы файлов, которые вы не используете - это дело для close(pfds[0]). Неиспользуемые дескрипторы открытых файлов потребляют пространство и ресурсы, поэтому держите его открытым, если вы не собираетесь его использовать?

close(pfds[1]) является немного более тонким, хотя. Трубы сообщают о завершении файла только в том случае, когда в буфере труб больше нет данных и нет активных авторов, то есть нет живых процессов, у которых труба открыта для записи.Если вы не закроете pfds[1] в родительском, программа будет висеть вечно, потому что wc(1) никогда не увидит конца ввода, так как есть процесс (wc(1)), который имеет трубу, открытую для записи, и как таковой может (но не будет) напишите больше данных.

Tl; DR: close(pfds[0]) - это просто хорошая практика, но не обязательная; close(pfds[1]) абсолютно необходим для обеспечения правильности программы.

-1

Вопрос 1: Да, вполне возможно, что «close (0)»; (в родительском) выполняется до «dup (pfds [1]); (у ребенка). Но так как это происходит в разных процессах, у ребенка все равно будет открыто fd 0.

Вопрос 2: Это хорошая практика бухгалтерского учета, чтобы закрыть конец трубы, который процесс не собирается использовать. Таким образом, вы можете избежать ошибок в будущем в более сложных программах. В описанном выше сценарии дочерний процесс должен когда-либо читать только из трубы. Если вы закроете конец записи в дочернем элементе, попытка eny записать на него вызовет ошибку, в противном случае у вас может быть ошибка, которую трудно обнаружить.

+0

Как ребенок все еще будет открывать fd 0? файловый дескриптор, совместно используемый в процессе, и dup() принимают самый низкий доступный FD. Я не могу понять. –

+0

fd 0 делится через вызов fork(). Но после этого каждый процесс имеет свою собственную память и ресурсы. Таким образом, родительский элемент может закрыть fd 0, а затем он может использоваться для вызова dup(). Это ничего не делает для fd 0 у ребенка, который все еще указывает на stdin. –

+0

Вопрос 2 на самом деле не о хороших практиках ведения бухгалтерского учета, есть намного больше, чем это. Попробуйте удалить 'close (pfds [1])', и вы останетесь с висячей программой. [Подсказка: трубы не сообщают EOF, когда есть хотя бы писатель] –

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