Запустить дочерний процесс

dimagolov

Новичок
22107 это pid дочки, 22101 это может быть pid сдохнувшего sh, по крайней мере согласно тому, что ты написал
 

point

Новичок
У меня тоже php5-fpm 5.2.10 0.5.13

В фоне в вебе запускается (отложенные задачи через это сделаны), и в фоне в консоле запускается. Сейчас попробую в стандартном Ubuntu-овском окружении это сделать.

-~{}~ 27.08.09 11:40:

Ubuntu 9.04, php5 5.2.6 mod_php, apache2 2.2.11.
Все из стандартного убунтовского репозитария.
PHP:
system(dirname(__FILE__)."/1.sh > /dev/null 2>&1 &");
где 1.sh
Код:
#/bin/sh
sleep 10
Захожу браузером. Сразу передает управление команде, следующей за system.

1.sh должен иметь права +x для пользователя/группы, от которого запущен php.

Без перенаправления или без амперсанда в конце как и положено ждет указанные 10 сек и передает управление дальше.
 

phprus

Moderator
Команда форума
grigori
ежу понятно, что сам процесс к этому отношения не имеет
но почему так и что это значит - я не знаю
При выполнении fork открытые файлы и сокеты наследуются дочерним процессом. exec, который подменяет копию процесса на другой исполняемый файл не закрывает открытые файлы и сокеты по этому и получается что дочерний процесс унаследовал открытый сокет предка.
 

Alexandre

PHPПенсионер
ри выполнении fork открытые файлы и сокеты наследуются дочерним процессом. exec, который подменяет копию процесса на другой исполняемый файл не закрывает открытые файлы и сокеты по этому и получается что дочерний процесс унаследовал открытый сокет предка.
и чтоб не рождать зомбиков я и использую сишную форкалку :)
правда кода чуточку больше, но если интересует то могу все выложить сегодня вечером (убрать лишнее надо из проекта).
 

phprus

Moderator
Команда форума
Alexandre
и чтоб не рождать зомбиков я и использую сишную форкалку
Я вот пока не могу понять, где в примере grigori могут возникать зомби. Может он просто словил момент, когда процесс уже умер, но его предок еще не прочитал его статус? (у меня такое иногда top показывает из-за того, что он не реалтаймовый, а обновляет информацию через некоторые промежутки времени).

Хотя есть подозрение, что в случае system ( "/usr/local/bin/php sleep.php &" ); PHP определяет окончание ожидания по закрытию файлового дескриптора, который связан с дочерним процессом и только в случае закрытия этого дескриптора на том конце PHP считывает статус умершего процесса, но & заставляет sh, форкнуться и тут-же умереть (но ввод/вывод то новый процесс наследует от sh), по этому PHP думает что его дочка все еще работает не смотря на то, что работает то внук, а дочерний процесс уже мертв.

dimagolov
Все что он мог, он исполнил, а вывод ему умереть не дает. Если делаем > /dev/null, то sh потоков никаких не получает от дочки и соответственно дохнет естественной смертью.
<defunct> - это процесс зомби, который уже умер. Его исполняемый код уже выгружен из памяти, все дискрипторы закрыты, а ресурсы освобождены. Тоесть никаким вводом выводом он заниматься не может, потому что процесса уже нет. В таблице процессов ядра осталась только информация о его смерти и его код завершения.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
dimagolov, я два раза запускал просто, потому pidы разные, на самом деле один

Alexandre
выкладывай, интересно

phprus
>Может он просто словил момент, когда процесс уже умер
sh был defunct все 10 секунд
 

phprus

Moderator
Команда форума
grigori
sh был defunct все 10 секунд
А в случае "prog > /dev/null 2>&1 &" Программа действительно запускается в фоне и не умирает по вине PHP через некоторое время?

Если да, то тогда скорее всего мое предположение:
Хотя есть подозрение, что в случае system...
верно и блокировка PHP возникает из-за открытых PHP файловых дескрипторов для связи с стандартным вводом/выводом дочернего процесса. (В случае /dev/null 2>&1 потоки дочернего процесса связываются с /dev/null, а дескрипторы, которые создал PHP будут закрыты sh в момент смерти)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
да, она жила (спала) все 10 секунд
воркеры php-fpm работу не прекращали, могу попробовать остановить их при работающей дочке

-~{}~ 27.08.09 23:31:

а про какую "блокировку PHP" речь?
PHP ждет только без &, без перенаправления вывода PHP все-равно свободен
 

phprus

Moderator
Команда форума
grigori
а про какую "блокировку PHP" речь?
PHP ждет только без &, без перенаправления вывода PHP все-равно свободен
А как тогда понять вот это:
однако ...

system ( "/usr/local/bin/php sleep.php &" );
ждем дочку
А точнее фразу "ждем дочку"? Если PHP ничего не ждет, то кто ждет дочку или что под этим подразумевается?

Пойду ка я пожалуй посмотрю, как в PHP на самом деле system реализован.
 

Alexandre

PHPПенсионер
Пойду ка я пожалуй посмотрю, как в PHP на самом деле system реализован.
реализовано через popen(); http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/exec.c?view=markup

Код:
89 	 [b]stream = php_stream_fopen_from_pipe(fp, "rb");[/b]
90 	
91 	buf = (char *) emalloc(EXEC_INPUT_BUF);
92 	buflen = EXEC_INPUT_BUF;
93 	
94 	if (type != 3) {
95 	b = buf;
96 	
97 	while ([b]php_stream_get_line(stream, ZSTR(b), EXEC_INPUT_BUF, &bufl)[/b]) {
98 	/* no new line found, let's read some more */
99 	if (b[bufl - 1] != '\n' && ![b]php_stream_eof(stream)[/b]) {
100 	if (buflen < (bufl + (b - buf) + EXEC_INPUT_BUF)) {
101 	bufl += b - buf;
102 	buflen = bufl + EXEC_INPUT_BUF;
103 	buf = erealloc(buf, buflen);
104 	b = buf + bufl;
105 	} else {
106 	b += bufl;
107 	}
108 	continue;
109 	} else if (b != buf) {
110 	bufl += b - buf;
111 	}
112 	
113 	if (type == 1) {
114 	int ob_level;
115 	PHPWRITE(buf, bufl);
116 	if ((php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL, &ob_level TSRMLS_CC) == SUCCESS) && ob_level < 1) {
117 	sapi_flush(TSRMLS_C);
118 	}
119 	} else if (type == 2) {
120 	/* strip trailing whitespaces */
121 	l = bufl;
122 	while (l-- && isspace(((unsigned char *)buf)[l]));
123 	if (l != (bufl - 1)) {
124 	bufl = l + 1;
125 	buf[bufl] = '\0';
126 	}
127 	add_next_index_stringl(array, buf, bufl, 1);
128 	}
129 	b = buf;
130 	}
131 	if (bufl) {
132 	/* strip trailing whitespaces if we have not done so already */
133 	if (type != 2) {
134 	l = bufl;
135 	while (l-- && isspace(((unsigned char *)buf)[l]));
136 	if (l != (bufl - 1)) {
137 	bufl = l + 1;
138 	buf[bufl] = '\0';
139 	}
140 	}
141 	
142 	/* Return last line from the shell command */
143 	RETVAL_STRINGL(buf, bufl, 1);
144 	} else { /* should return NULL, but for BC we return "" */
145 	RETVAL_EMPTY_STRING();
146 	}
147 	} else {
148 	while((bufl = [b]php_stream_read(stream, buf, EXEC_INPUT_BUF)[/b]) > 0) {
149 	PHPWRITE(buf, bufl);
150 	}
151 	}
152 	
153 	[b]pclose_return = php_stream_close(stream);[/b]
154 	efree(buf);
 

phprus

Moderator
Команда форума
Alexandre
Это я уже посмотрел. popen это в любом случае fork + exec, так как по другому в *nix процесс создать нельзя.

Я не могу понять, как соотносятся фразы grigori:
PHP все-равно свободен
и
Кто кого ждет то и как это выражается?

Кстати приведенный код говорит, что ожидание возможно только из-за потока вывода запускаемого приложения. PHP "подвисает" на чтении из него.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>PHP все-равно свободен
я ошибся. воркер занят, ждет возврата
 

point

Новичок
> Кстати приведенный код говорит, что ожидание возможно только из-за потока вывода запускаемого приложения.

"Теория" сходится с практикой. Непоятно только, почему у Alexandre тестовый пример не работает как ожидается...
 

no_santa

Снегур
В мане exec('script',$out) - если $out != FALSE - родитель не ждет и не прерывает дочерний процесс.
Суть моего вопроса - как написать "void" на PHP в данном случае.
 

point

Новичок
Вы хотите вместо $out void написать ? Это опциональный параметр, его можно опустить.
 

no_santa

Снегур
Опускаю - дочка умирает с папой.
Сейчас костыля ради засунул еще один лог. Работает, но мне стыдно.
 

phprus

Moderator
Команда форума
grigori
я ошибся. воркер занят, ждет возврата
Тогда все верно. В случае если не перенаправить вывод запускаемого процесса куда-либо он заблокирует php.
Так как popen - это fork + exec, то происходит следующее:

1) Процесс PHP создает pipe (канал) для взаимодействия с дочерним процессом
2) Процесс PHP делает fork и привязывает один конец канала к стандартному выводы дочернего процесса.
3а) Родитель блокируется на read из канала.
3б) Дочерний поток подменяет себя при помощи exec*
4) Дочерний поток работает. Даже если он запущен в фоне, то его стандартный вывод все-равно привязан к php, так как при fork дескрипторы файлов наследуются.

Если запускать дочку с > /dev/null 2>&1 &, то стандартный вывод дочернего процесса отвязывается от канала и php уже не блокируется, так как читать ему уже не откуда.

Зомби-же, если не использовать перенаправление вывода дочернего процесса куда либо, возникает из-за этого участка кода:
Код:
75 	#if PHP_SIGCHILD
76 	sig_handler = signal (SIGCHLD, SIG_DFL);
77 	#endif
...
157 #if PHP_SIGCHILD
158 if (sig_handler) {
159 	signal(SIGCHLD, sig_handler);
160 }
161 #endif
Обработчик сигнала SIGCHLD по умолчанию не считывает состояния детей и по этому они становятся зомби. Когда-же обработчик сигнала восстанавливается php считывает статус ребенка и зомби пропадает.
По этому в случае если PHP блокируется на чтении из потока sh висит в виде зомби.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
а что толку, если каналы привязаны и не закрыты остаются
ничего не меняется
 
Сверху