php fork/wait, strange behaviour

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • RedWiz

    php fork/wait, strange behaviour

    Hi

    i have to develop a multihreaded php application on linux, then through
    pcntl_fork and wait.
    I tried it, but there something going wrong, i think.
    The difference whit other languages like c and python is that the wait
    cannot handle correctly all signals from dead children in two cases:

    1 - two or more children dies (about) at the same time time
    2 - the chidren dies before pcntl_wait start

    in fact the wait does not return the chld's pid, but "-1"
    that is he knows that a child is dead, but he cannot say the correct
    pid.

    I made two scripts (below), one php and one python that should do the same
    thing. The python one run correctly , the php no.
    You can verify their behaviour, if you want.
    You can comment, o indecrease or increase the sleep call in the php script
    to note what happend at the wait call
    At the end i ask you, am i doing someting wrong?
    Is the php fork/wait behaviour bugged?

    thanks in advance

    Andrea
    #!/usr/bin/php
    <?php
    $children = array();

    function child($id)
    {
    $p=posix_getpid ();
    echo "child: ($id) pid ($p)\n";
    sleep(rand(1,5) );
    echo "child:end pid ($p)\n";

    exit(0);
    }
    $i=0;
    while($i<10)
    {
    $pid = pcntl_fork();

    if($pid == -1)
    die("Could not fork!");
    elseif($pid == 0)
    child($i);
    else
    {
    $children[] = $pid;
    $i++;
    }
    }

    print "dad:sleep a bit...\n";
    $i=10;
    while($i)
    {
    $pid_dead = pcntl_waitpid(-1,$status);
    if ($pid_dead != 0)
    {
    echo "dad:dead child pid ($pid_dead)\n";
    if(array_search ($pid_dead,$chi ldren))
    {
    unset($children[$pid_dead]);
    print "dad:unset pid ($pid_dead)\n ";
    $i--;
    }
    else
    {
    $i--;
    print "dad:pid ($pid_dead) not tracked\n";
    }
    }
    }

    echo "dad: all dead\n"
    ?>


    #!/usr/bin/python

    import sys
    import os
    import time

    def child(i):
    print "child: (%d) pid (%d)" % (i,os.getpid())
    sys.exit(0);


    children=[]
    i=0
    while i<10:
    i+=1
    pid = os.fork()
    if not pid:
    child(i)
    else:
    children.append (pid)

    print "dad:sleep a lot..."
    time.sleep(2)
    while len(children):
    pid_dead = os.waitpid(-1,os.WNOHANG)

    if pid_dead[0] != 0:
    print "dad:dead pid (%d)" % pid_dead[0]
    try:
    children.index( pid_dead[0])
    children.remove (pid_dead[0])
    print "dad:elimin ato pid (%d) " % pid_dead[0]
    except:
    print "dad:pid (%d) not in children" %
    pid_dead[0]
    time.sleep(0.5)
    print "dad: all dead"

  • =?ISO-8859-15?Q?Iv=E1n_S=E1nchez_Ortega?=

    #2
    Re: php fork/wait, strange behaviour

    RedWiz wrote:
    Hi
    >
    i have to develop a multihreaded php application on linux, then through
    pcntl_fork and wait.
    I tried it, but there something going wrong, i think.
    The difference whit other languages like c and python is that the wait
    cannot handle correctly all signals from dead children in two cases:
    >
    1 - two or more children dies (about) at the same time time
    2 - the chidren dies before pcntl_wait start
    >
    in fact the wait does not return the chld's pid, but "-1"
    that is he knows that a child is dead, but he cannot say the correct
    pid.
    In your case, it's an array problem. You are handling the $children array
    the wrong way.
    {
    $children[] = $pid;
    $i++;
    }
    Thsi will create an array like (0=>1234, 1=>1235, 2=>1236).
    if(array_search ($pid_dead,$chi ldren))
    {
    unset($children[$pid_dead]);
    print "dad:unset pid ($pid_dead)\n ";
    $i--;
    }
    What happens here if $pid_dead is 1234? You'll never unset the element 0 of
    the array.


    You have two options:
    - RTFM on array_search, and check for a boolean false return value (hint:
    use the === operator)
    - Instead of storing the PIDs in the array as the contents, store the PIDs
    as the keys, like this:
    $children[$pid] = true;
    And try using ( isset($children[$pid]) ) as the condition for the "if"
    statement.


    AFAIK, there is nothing wrong with the pcntl functions. If several children
    die very close to each other, they'll be left as zombies until the parent
    waits for every one of them.


    Cheers,
    --
    ----------------------------------
    Iván Sánchez Ortega -ivansanchez-algarroba-escomposlinux-punto-org-

    Proudly running Debian Linux with 2.6.24-1-amd64 kernel, KDE 3.5.8, and PHP
    5.2.5-2 generating this signature.
    Uptime: 18:35:54 up 8 days, 5:20, 4 users, load average: 0.87, 0.80, 0.66

    Comment

    • RedWiz

      #3
      Re: php fork/wait, strange behaviour

      >
      Thsi will create an array like (0=>1234, 1=>1235, 2=>1236).
      yes
      >if(array_searc h($pid_dead,$ch ildren))
      >{
      >unset($childre n[$pid_dead]);
      >print "dad:unset pid ($pid_dead)\n ";
      >$i--;
      >}
      >
      What happens here if $pid_dead is 1234? You'll never unset the element 0 of
      the array.
      you're right, that is an error, but it doesn't interfere with the wait
      call.
      Cause in every way, wait return some "-1"s
      AFAIK, there is nothing wrong with the pcntl functions. If several
      children die very close to each other, they'll be left as zombies until
      the parent waits for every one of them.
      going to find some example.

      ty

      Comment

      • =?ISO-8859-15?Q?Iv=E1n_S=E1nchez_Ortega?=

        #4
        Re: php fork/wait, strange behaviour

        RedWiz wrote:
        Cause in every way, wait return some "-1"s
        Using your example, wait never returned -1 in my computer.

        --
        ----------------------------------
        Iván Sánchez Ortega -ivansanchez-algarroba-escomposlinux-punto-org-

        MSN:i_eat_s_p_a _m_for_breakfas t@hotmail.com
        Jabber:ivansanc hez@jabber.org ; ivansanchez@kde talk.net

        Comment

        Working...