LINUX.ORG.RU

fork()+exec()+pipe()

 , ,


0

2

Здравствуйте. Вопрос по коду:

 1 pid_t pid;
 2 pid = fork ();
 3 if (pid == –1)
 4 perror ("fork");
 5 /* дочерний ... */
 6 if (!pid) {
 7 const char *args[] = { "windlass", NULL };
 8 int ret;
 9 ret = execv ("/bin/windlass", args);
10 if (ret == –1) {
11 perror ("execv");
12 exit (EXIT_FAILURE);
 }
}

Родительский процесс продолжает выполняться, как и ранее, за исключением появления у него нового дочернего.
Вызов execv() влияет только на дочерний про­цесс, заставляя его выполнить программу /bin/windlass.

Почему execv() применяется именно к дочернему, созданному fork(), процессу, а не к родительскому?

Второй вопрос: есть дерево (не суть какое). запускается процесс и далее используя структуру (ациклический граф) список «разворачивается» в соответствующую графу структуру процессов, отсекая от графа себя и передавая остаток графа дальше. в родителе создаю pipe(), а далее он наследуется. вопрос, собственно: процессы (узлы графа) смогут между собой коммуницировать используя один, созданный родителем, pipe или надо для каждой пары узлов отдельный pipe делать?

бл@, где вы так изъясняться учитесь?

Почему execv() применяется именно к дочернему, созданному fork(), процессу, а не к родительскому?

собссно после этого вопроса можно отправить курить теорию. дальше вообще мракобесие, ад и пакистан.

anonymous ()

Родительский процесс продолжает выполняться, как и ранее, за исключением появления у него нового дочернего.
Вызов execv() влияет только на дочерний про­цесс
Почему execv() применяется именно к дочернему, созданному fork(), процессу, а не к родительскому?

По проверке кода возврата fork, вместо которой мы вынужнены наблюдать загадочное

 5 /* дочерний ... */
? Соберись, выложи минимальный (не)работающий пример, задай вопрос, как подобает.

t184256 ★★★★★ ()

TL;DR: execv не возврещается, а замещает собой процесс.

beastie ★★★★★ ()
Ответ на: комментарий от t184256

это пример из книги «Linux. Системное программирование» автор Р.Лав. стр. 180. пример без моей корректировки.

Snorri ()
Ответ на: комментарий от beastie

Родительский процесс продолжает выполняться, как и ранее, за >исключением
появления у него нового дочернего. Вызов execv() влияет только на >дочерний про­цесс, заставляя его выполнить программу /bin/windlass.

на этом месте вопрос и возник «почему exec применяется именно к дочернему процессу?»

Snorri ()
Ответ на: комментарий от Snorri

на этом месте вопрос и возник «почему exec применяется именно к дочернему процессу?»

man fork.

RETURN VALUE

On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.

А теперь посмотри, где выполняется exec.

theNamelessOne ★★★★★ ()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от t184256

По проверке кода возврата fork

пример из другой книги:

1 if ((pid1 = fork ()) == 0) {
2 close (pf[0]);
3 execl ("./pipe1-src", "pipe1-src",
4 spf[1], NULL);
5 fprintf (stderr, "exec() [src] error\n");
6 return 1;
 }
имеется в виду строка 1? эта проверка - просто условие. как оно может влиять на то, что выполняется внутри опреторных скобок?

Snorri ()

man fork

Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent process. Otherwise, a value of -1 is returned to the parent process,
no child process is created, and the global variable errno is set to indicate the error.

Далее у тебя execv выполняется если !pid, то есть pid == 0, где pid – возврат fork.

Deleted ()
Ответ на: комментарий от Snorri

Из-за лапши с if'ами там чёрт ногу сломит. Вот тебе каонiчный пример использования fork + exec:

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

int
main()
{
	pid_t pid;
	int rv;

	switch (pid = fork()) {
	case -1: /* error */
		perror("fork");
		exit(EXIT_FAILURE);
		break;
	case 0: /* child */
		execlp("/bin/echo", "/bin/echo", "hello", "from", "child");
		/* NOTREACHED */
		perror("execl");
		exit(EXIT_FAILURE);
		break;
	default: /* parent */
		printf("wait for %d\n", pid);
		wait(&rv);
		printf("ret val: %d\n", rv);
		break;
	}
	return 0;
}

1-е домашнее задание: добавить pipe.

2-е домашнее задание: всё выкинуть и использовать popen. ;)

beastie ★★★★★ ()
Ответ на: комментарий от Snorri

Ай, мой косяк, проглядел строку 6. exec применяется именно к дочернему процессу, потом что он в блоке if'а из строки 6. выравнивай код что ли...

t184256 ★★★★★ ()
Ответ на: комментарий от theNamelessOne

On success, the PID of the child process is returned in the >parent, and 0 is returned in the child. On failure, -1 is >returned in the parent, no child process is created, and errno is >set appropriately.

да, понятно

pid_t fork(void);
возвращает pid дочернего процесса, но мы же при вызове execv() никакого pid не указываем, а exec() замещает собой вызывающий процесс, а вызывает ведь родительский. строка 2 исходного примера создает дочерний процесс, получает его pid. затем в строке 6 проверяет, что процесс нормально стартанул и строкой 9 вызывает exec

Snorri ()
Ответ на: комментарий от beastie

Из-за лапши с if'ами там чёрт ногу сломит.

к автору книги (Р.Лав) тогда претензии

Snorri ()
Ответ на: комментарий от Snorri

Всё не так.

pid_t pid = fork();

if (pid == -1) { // ошибка fork
  // ...
}

if (!pid) { // pid = 0
  // это код, который выполняет дочерний процесс

  ret = exec(/* ... */);
} else { // pid != 0
  // это код, который выполняет родительский процесс
}

exec выполняется в ветке дочернего процесса. Именно поэтому ¨exec применяется к дочернему процессу¨

theNamelessOne ★★★★★ ()
Ответ на: комментарий от Snorri

эта проверка - просто условие. как оно может влиять на то, что выполняется внутри опреторных скобок?

Считай, что код, который идёт после fork, выполняется два раза — родительским и дочерним процессом. Чтобы отличить их друг от друга, используется возвращаемый pid.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от Snorri

к автору книги (Р.Лав) тогда претензии

А выложи-ка фотографию этой страницы из книги. В русских переводах, конечно, часто бывают опечатки, но чтобы вот так покорёжили код — верится с трудом.

i-rinat ★★★★★ ()
Ответ на: комментарий от theNamelessOne

Даже не «считай», а так оно и есть. После fork у нас уже 2 абсолютно одинаковых процесса. Единстенная разница между ними, что в одном pid == 0, а в другом pid == <pid другого процесса>.

beastie ★★★★★ ()
Ответ на: комментарий от Deleted

Upon successful completion, fork() returns a value of 0 to the child process

получается что в дочернем процессе pid==0; понял... во «в пня въехал»

Snorri ()
Ответ на: комментарий от beastie

А нечего читать кривых авторов.

Чем тебе Robert Love кривой?

Snorri, скорее всего, какую-нибудь epub-эдишн читает.

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Честно признаться в первый раз про него слышу. ;) Мну учил C по K&R, devil book и чтению сырцов.

PS: авторы часто грешат читабельностью для экономии места на странице. Т.ч. может быть оно и в оригинале покорёжено.

beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от beastie

Мну учил C по K&R, devil book и чтению сырцов. K&R разумеется, но это именно Си. Сэджвик хорош. А Лав это именно по программированию под Linux

Snorri ()
Ответ на: комментарий от beastie

Мну учил C по K&R

Я учил Си по сообщениям об ошибках от компилятора. И по статьям «Почему делать вот так — плохо.»

i-rinat ★★★★★ ()
Ответ на: комментарий от Snorri

Ссылка на файл, который надо ещё скачать и открыть страницу. Файла, кстати, там уже нет, срок хранения истёк.

В общем, если в книжке, которую ты читаешь, текст программ оформлен так же ужасно, как ты привёл в заглавном сообщении темы, выброси эту книжку. Ты больше времени потратишь на борьбу с листингами и опечатками в них, чем на саму учёбу.

i-rinat ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.