Объясните пожулайста незнающему... pcntl_fork()

GrayMaster

Новичок
Объясните пожулайста незнающему... pcntl_fork()

Объясните пожалуйста, как при выполнеии этого кода получается результат "1122" ?

PHP:
$a=0;
$pid = pcntl_fork();
if ($pid) {
        $a++;
        echo $a;
        sleep(2);
        $a++;
        echo $a;
} else {
        sleep(1);
        $a++;
        echo $a;
        sleep(1);
        $a++;
        echo $a;
}
Заранее спасибо.
 

Tor

Новичок
со строки
if ($pid) {
это уже две отдельные программы, не имеющие ничего общего
поэтому
первая выводит 1
вторая выводит 1
первая выводит 2
вторая выводит 2
 

GrayMaster

Новичок
вроде бы разобрался...

Теперь вот такой вопрос... Как главным процессом дождаться пока потомки закончат работу ?

PHP:
$pids = array();

for ($i = 1; $i < 3; $i++ ) {
        $pid = pcntl_fork();
        if ($pid == -1) {
                echo "can't fork\n";
                die();
        } elseif ($pid) {
                $pids[] = $pid;
                echo "i'm parent #$pid ($i)\n";
        } else {
                sleep(1);
                echo "i'm child ($i)\n";
                exit();
        }
}

foreach ($pids as $pid) {
        echo $pid."\n";
}
 

GrayMaster

Новичок
PHP:
do {
        $child_pid = pcntl_waitpid(-1, $status, WNOHANG);
        
        sleep(10);
} while ($child_pid <= 0);
гуд ? :)
Зависать нечему, или ещё какие-либо проверки сделать ?
 

GrayMaster

Новичок
PHP:
$pids[] = $pid;
Вот я их записываю в масив, но как их обрабатывать правильно в конце ?
 

Screjet

Новичок
Автор оригинала: GrayMaster
PHP:
$pids[] = $pid;
Вот я их записываю в масив, но как их обрабатывать правильно в конце ?
PHP:
$pids_hash = array_flip($pids);

while( ($cnt=count($pids_hash)) ){
  $pid = pcntl_wait(-1, $status);
  unset($pids_hash[$pid]);
  if ( $status ){
     //.. анализируем ошибку
  }
  if ( $cnt < 5 ){
    //.. запускаем следующие процессы
  }
}
Это примерно как у меня сделано. Придумаешь чтото получше - напиши.
 

GrayMaster

Новичок
Непонял что тыт тут делаешь... Распиши пожалуйста этот цикл - как он работает...
Спасибо... ;)
 

Screjet

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

GrayMaster

Новичок
Т.е. скрипт на строке
PHP:
$pid = pcntl_wait(-1, $status);
останосится, пока какой-то из процессов не умрёт ?

И зачем делать array_flip() ?

-~{}~ 05.11.05 20:07:

У меня получилась вот такая структура прграммы:
PHP:
$num_forks = 10;

$pids = array();

for ($i = 0; $i < $num_forks; $i++ ) {
        $pid = pcntl_fork();
        if ($pid == -1) {
                die("can't fork\n");
        } elseif ($pid) {
                $pids[] = $pid;
        } else {
                // код потомка
                exit();
      }
}

$pids_hash = array_flip($pids);

while (($cnt = count($pids_hash))){
        $child_pid = pcntl_waitpid(-1, $status);
        unset($pids_hash[$child_pid]);

        if ($status) {
                // анализ ошибки
        }

        if ($cnt < $num_forks) {
                // запуск нового форка
        }
}
Только вот непонятки с этим куском:
PHP:
        if ($cnt < $num_forks) {
                // запуск нового форка
        }
Как мне лучше всего создать новго потомка ? Запихать код потомка в файл, и include'ить что-ли ? :D По моему бредовый вариант :)
 

Screjet

Новичок
Нет. Вызываешь ф-цию потомка (если нужно = с аргументами), типа
PHP:
exec_child($args);
А в ф-ции пишешь код, который выполняет полезную работу, типа
PHP:
function exec_child( $args=null ){
  echo "Im child with PID:".posix_getpid()."\n";
}
 

mani13

Новичок
либо сделать проще:
PHP:
$pids = array();
$max = 5;
$status = 0;
while (true) {
   if (count($pids) > $max) {
      $child_pid = pcntl_waitpid(-1, $status);
      unset($pids[array_search($child_pid, $pids)]);
   }
   $pid = pcntl_fork();
   if ($pid == -1) {
      die('could not fork');
   } else if ($pid) {
      $pids[] = $pid;
   } else {
      // child
   }
}
 

GrayMaster

Новичок
Ой :) Ступил я :)
Мне внизу страницы в блоке:
PHP:
        if ($cnt < $num_forks) { 
                // запуск нового форка 
        }
, ведь тоже нужно будет использовать pcntl_fork() - для создания потомка, а затем в ней exec_child() ?
 

Screjet

Новичок
GrayMaster
Подели хотя бы на ф-ции красиво:
одна запускает _число_ форков,
другая выполняет чайлды
[, тертья анализирует статус чайлда]
и т.д.

зы. Каша из топора бывает только в сказке.
 

GrayMaster

Новичок
одна запускает _число_ форков,
другая выполняет чайлды
С этим нет проблем. Большое спасибо, с Вашей помощью в этом разобрался...

[, тертья анализирует статус чайлда]
А вот с этим проблемы... Зачем анализировать статус, в каких случаях это необходимо ?
 

Screjet

Новичок
Зачем анализировать статус
Для обратной связи.
в каких случаях это необходимо
Чайлд не отработал аргумент и умер.. Но посмертно выслал статус ошибки. Родитель пометил аргумент как убийцу и больше никому его не назначает.

Вобщем не заморачивайся. Не нужен = не используй.
 

GrayMaster

Новичок
Для обратной связи.
Ааа, нет :) раз для этого - то нужен :)
Как раз хотел задавать следующий вопрос - как связать потомков с основным процессом :)

Спасибо за наводку, пошёл рыться в доках pcntl_signal...

-~{}~ 06.11.05 02:10:

Эх... Проблема за проблемой :( Ужас :(
вобщем в результате пришёл к такой структуре:
PHP:
while ($do) {
        if (count($pids) >= $config['spam']['count_fork']) {
                $child_pid = pcntl_waitpid(-1, $status);
                unset($pids[array_search($child_pid, $pids)]);
        }

        $pid = pcntl_fork();

        if ($pid == -1) {
                die("Could not fork!");
        } elseif ($pid) {
                $pids[] = $pid;
        } else {
                child_exec($i);
                exit();
        }
        
        $i++;
}
У меня в скрипте заранее просчитать нельзя сколько будет создано потомков / сколько будет выполнено операций всеми потомками...

Указываю в конфиге:
1. кол-во потомков
2. кол-во операций выполняемых потомком

child_exec($i); // $i - точко входа

В какой-то момент, потомок сможет определить, что выполнение общей программы завершено. Это нужно передать основному процессу, и сделать $go = false...

Подскажите пожалуйста как это реализовать ?

ЗЫ: Надеюсь это последний вопрос :)
 

nerezus

Вселенский отказник
Хм, вопрос в тему: в какой библиотеке эта функция находится?
Просто хотел попробовать - ф-ия не найдена.
 
Сверху