Мне нужен «вечный» процесс, который проходит через таблицу MySQL и порождает дочерние процессы. Псевдокод:
while(true)
$rows = SELECT * FROM workers
foreach($rows as $row){
DELETE $row->id
spawn_child($row->id)
}
sleep(5)
}
function spawn_child($id){
$pid = pcntl_fork()
if($pid <0){
//err
}elseif($pid == 0){
//child
exec("worker_program $id");
exit();
}elseif($pid > 0){
//parent
}
}
Проблема в том, что, когда дочерний процесс возвращается из worker_program и завершает работу, он закрывает явно разделяемый дескриптор mysql, поэтому родительский процесс получает ошибку " Msql Сервер ушел ".
Как мне это решить? Это ошибка дизайна?
Как создать и отсоединить процесс в PHP без совместного использования каких-либо ресурсов БД и т. Д., Чтобы дочерний процесс мог свободно выходить?
(Я попробовал: setsid и снова разветвляться, вызывая работников с 'worker_program &
' вместо разветвления в php, но это не работает вообще (странно?). Я использую PDO. Также ребята из php.net говорят, что это не ошибка. Это на osx и php5.3 (и на debian).)
Refs:.
php.net / bug: "Родительский процесс потерял соединение с MySQLi после того, как дочерний процесс пропал"
Update / обходной путь
Итак, я наконец нашел способ справиться с этим. Что работает, так это использование popen
для порождения рабочих процессов. Таким образом, кажется, что создается совершенно «свежий» процесс без каких-либо акций. Затем я позволяю ребенку разветвляться и отсоединяться. Так в мастер-процессе вместо pcntl_fork
или exec
:
$p = popen("worker_program $arg","r");
sleep(1); //give it time to detach (won't work otherwise. Any other ideas?)
pclose($p);
А потом в рабочей программе:
#!/usr/bin/env php
<?php
//fully detach from parent, as proposed by the 'gurus'
//(Why can't this be done with only one fork?)
if(pcntl_fork()) {
exit();
}
posix_setsid();
if(pcntl_fork()) {
exit();
}
...