Home | MySQL Russian Manual | MySQL Manual | Apache HTTP Server Rus Documentation | Apache HTTP Server Documentation | downloads | faq

search for in the  Language: Russian


pcntl_fork

(PHP 4 >= 4.1.0, PHP 5)

pcntl_forkForks the currently running process

Description

int pcntl_fork ( void )

The pcntl_fork() function creates a child process that differs from the parent process only in its PID and PPID. Please see your system's fork(2) man page for specific details as to how fork works on your system.

Return Values

On success, the PID of the child process is returned in the parent's thread of execution, and a 0 is returned in the child's thread of execution. On failure, a -1 will be returned in the parent's context, no child process will be created, and a PHP error is raised.

Examples

Example #1 pcntl_fork() example

<?php

$pid 
pcntl_fork();
if (
$pid == -1) {
     die(
'could not fork');
} else if (
$pid) {
     
// we are the parent
     
pcntl_wait($status); //Protect against Zombie children
} else {
     
// we are the child
}

?>

See Also


User Contributed Notes
pcntl_fork
Anonymous
19-Nov-2009 06:12
With regards to the database connection, one could deal with this using kill 9 or a sleep, the real problem is if two threads make a database query at the same time, PHP starts having random database errors that are not necessarily clear as to what the problem is.

You should create a separate link per thread.
Tony
29-Oct-2009 11:05
If you want to execute some code after your php page has been returned to the user. Try something like this -

<?php
function index()
{
        function
shutdown() {
           
posix_kill(posix_getpid(), SIGHUP);
        }

       
// Do some initial processing

       
echo("Hello World");

       
// Switch over to daemon mode.

       
if ($pid = pcntl_fork())
            return;    
// Parent

       
ob_end_clean(); // Discard the output buffer and close

       
fclose(STDIN);  // Close all of the standard
       
fclose(STDOUT); // file descriptors as we
       
fclose(STDERR); // are running as a daemon.

       
register_shutdown_function('shutdown');

        if (
posix_setsid() < 0)
            return;

        if (
$pid = pcntl_fork())
            return;    
// Parent

        // Now running as a daemon. This process will even survive
        // an apachectl stop.

       
sleep(10);

       
$fp = fopen("/tmp/sdf123", "w");
       
fprintf($fp, "PID = %s\n", posix_getpid());
       
fclose($fp);

        return;
}
?>
php at mx dot magic-lamp dot org
11-Sep-2009 08:31
A workaround for the MySQL "Lost Connection during query", or any other object related problems caused by children exiting is to force the child to kill -9 itself, thus avoiding any cleanup.  Sure - it's not too elegant, but it does work.

<?php
$pid
= pcntl_fork();
if (
$pid == 0 ) {
   
// This is the child process.  Do something here.
    // Instead of calling exit(), we use posix_kill()
   
posix_kill(getmypid(),9);
}
?>

Watch out that you don't spawn too many processes though as this creates its own problems.
drrota at us dot ibm dot com
22-Aug-2009 10:47
I was able to get around the problem of not being able to run fork and exec from Apache php.

I got around this by calling the system 'at' command on Linux.  "at run something now".  and you have to set atrun -s in a crontab file (to run every minute) to insure that things get kicked off quickly even if there is a heavy load on the machine.

If you're the only one running batch jobs on a linux box, this works.
pagan at o2 dot pl
23-Nov-2008 08:57
Mayby:

foreach ($cmds as $cmd) {
  $pid=pcntl_fork();
  if (!$pid) { // if we don't have a pid (pid = 0), we know that is a child
    exec($cmd);
    break;
  }
}
csrster at gmail dot com
12-Sep-2008 09:48
Here's one way to execute a bunch of commands in an array, each in its own process

foreach ($cmds as $cmd) {
  $pid=pcntl_fork();
  if ($pid) {
    exec($cmd);
    break;
  }
}

Don't forget the break statement!

I use this in a cli routine to rip a bunch of internet radio streams in parallel. This kind of parallelism is natural here because the download rate for each stream is limited by the network, not the cpu.
kentmussell at mindspring dot com
27-Nov-2007 06:05
Here is an interesting script I wrote.  It demonstrates how pcntl_fork() might be used as a useful tool.

<?php
/* This script serves the purpose of testing an algorithm designed to:
a.) Compare password hashes, or try passwords efficiently where the time to try a single password is 10 seconds. 
b.) Spawn threads to work simultaneously on comparing hashes.
c.) Restrict the number of threads open at a time. 
*/
//checks for divisibility
function divby($num,$den) {
   
$result = $num/$den;
   
$result2 = floor($result);
    if (
$result == $result2) {
        return
true;
        }
    else {
        return
false;
        }
    }
//checks whether a period of time fits into 2 second intervals occuring every 10 seconds.  Interval may increase or decrease in size to use more or less memory. 
function goodTime($elapsed) {
   
$num = floor($elapsed);
   
$num = $num/12;
   
$min = floor($num);
   
$min = 12*$min;
   
$max = $min+2;
    if (
$elapsed >= $min && $elapsed <= $max) {
        return
"yes";
        }
    else {
        return
"no";
        }
    }

$x = 30; //number of child threads
$pid = 1; //needed to create first thread
$xpass = md5('29');//hash to crack
$time = time();
$i = 1;
//parent spawns $x children.
while ($i <= $x) {
    if (
file_exists('childcall.txt')) {
       
unlink('childcall.txt');
        exit;
        }
   
$elapsed = time()-$time;
   
//children are only spawned during intervals occuring every 10 seconds leaving enough time for the previous batch of children to finish their task.
   
if (goodTime($elapsed)=="yes") {   
       
//Are we the parent?
       
if ($pid != 0) {
           
//Give birth to a child. 
           
$pid = pcntl_fork();
           
//create a record of how many children have been birthed.
           
$arr[$i] = $i;
           
$time2 = $elapsed;
            }
       
//escort children out of the loop.
       
if ($pid == 0) {
           
$i = $x+1;
            }
       
$i++;
        }
    }
//parent waits for children to finish playing.
if ($pid) {
   
$value = 1;
    while (!
file_exists('childcall.txt')) {
       
//wait
       
}
   
unlink('childcall.txt');
   
$time = time()+2;
    while (
time()<$time) {
       
//wait
       
}
    exit;
    }
//children take turns finding the highest array value, and changing it to 0
rsort($arr);
$value = max($arr);
$arr[$value] = 0;
$time = time()+10;
//simulate delay
while (time() < $time) {
   
//wait
   
}
//compare the high array value hash to the hash we are looking to crack.
if (md5($value) == $xpass) {
    echo
"$value \n";
    }
if (
$value == $x || md5($value) == $xpass) {
   
$file = "childcall.txt";
   
$content = true;
   
file_put_contents($file,$contents);
    }
?>
MagicalTux at kinoko dot fr
29-Oct-2007 06:30
QUOTE from arnold at helderhosting dot nl:

It is not possible to use the function 'pcntl_fork' when PHP is used as Apache module. You can only use pcntl_fork in CGI mode or from command-line.

Using this function will result in: 'Fatal error: Call to undefined function: pcntl_fork()'

==============================================

This is not true. I already had to use pcntl_fork() from PHP running as an Apache module so I know. By default, pcntl is disabled when php is compiled as an apache module, which is to be expected.

Forking in an apache module is rather complex, and one of the most important things you should remember is to let your child kill himself with SIGKILL. If you just call exit(), you might end having duplicate headers.
Forking from an Apache module is NOT RECOMMANDED unless you know what you do and fully understand how apache works.
underdog
20-Sep-2007 06:32
QUOTE from arnold at helderhosting dot nl:

It is not possible to use the function 'pcntl_fork' when PHP is used as Apache module. You can only use pcntl_fork in CGI mode or from command-line.

Using this function will result in: 'Fatal error: Call to undefined function: pcntl_fork()'

==============================================
THANKS, Arnold! This bears repeating... (Note to PHP documentation developers: Please add this important comment to the main documentation for this function - it would saved me a lot of time debugging!)
frans-jan at van-steenbeek dot net
30-May-2007 12:12
I've posted this here before, but the article has been down so my post got deleted.

I've written an in-depth look at pcntl_fork() which is available here:
http://www.van-steenbeek.net/?q=php_pcntl_fork
amatsak at chestnutsoftware dot com
25-Oct-2006 09:06
The reason for the MySQL "Lost Connection during query" issue when forking is the fact that the child process inherits the parent's database connection. When the child exits, the connection is closed. If the parent is performing a query at this very moment, it is doing it on an already closed connection, hence the error.

An easy way to avoid this is to create a new database connection in parent immediately after forking. Don't forget to force a new connection by passing true in the 4th argument of mysql_connect():

<?
// Create the MySQL connection
$db = mysql_connect($server, $username, $password);

$pid = pcntl_fork();
            
if (
$pid == -1 ) {       
   
// Fork failed           
   
exit(1);
} else if (
$pid ) {
   
// We are the parent
    // Can no longer use $db because it will be closed by the child
    // Instead, make a new MySQL connection for ourselves to work with
   
$db = mysql_connect($server, $username, $password, true);
} else {
   
// We are the child
    // Do something with the inherited connection here
    // It will get closed upon exit
   
exit(0);
?>

This way, the child will inherit the old connection, will work on it and will close upon exit. The parent won't care, because it will open a new connection for itself immediately after forking.

Hope this helps.
xuecan at google dot com
26-Aug-2006 04:59
I think this simple code can help understand how fork works:

<?
echo "posix_getpid()=".posix_getpid().", posix_getppid()=".posix_getppid()."\n";

$pid = pcntl_fork();
if (
$pid == -1) die("could not fork");
if (
$pid) {
    echo
"pid=".$pid.", posix_getpid()=".posix_getpid().", posix_getppid()=".posix_getppid()."\n";
} else {
    echo
"pid=".$pid.", posix_getpid()=".posix_getpid().", posix_getppid()=".posix_getppid()."\n";
}
?>
Jeff
21-Jul-2006 09:45
In response to Jon Dowland, a fork is actually not that expensive of an operation. Yes, a fork creates a copy of the process, so you would think it would be an expensive operation, but instead operating systems implement what is known as "copy-on-write." Instead of actually making a copy of the data, both processes reference the same data as long as they're only reading from it. Once a process goes to write to the data, then the child process gets its own copy of it. So, the majority of the PHP engine would not have to be copied and thus this would not be very expensive.
spam at kacke dot de
03-Mar-2006 06:52
I disagree too with reinoud at hyves dot nl too.

It seems youll always get the mysql-error 0 "lost connetion during query" when massive forking at the same time like
while x = mysql_fetch_array() -> fork

If you put for example a usleep between each fork youll dont loose the connection.

I figured that out sometimes and maybe its a "workaround" that helps

Toppi
rob at bronco dot co dot uk
26-May-2005 02:53
I disagree with reinoud at hyves dot nl. I have multiple examples of software which connects to a database then forks a great number of times, and every child has full access to the database link resource. The only issues with forking and MySQL that I have experienced is that you may get the occasional "MySQL server has gone away", although that particular error is probably more related to massively overloading a database.
arnold at helderhosting dot nl
13-Feb-2005 03:12
It is not possible to use the function 'pcntl_fork' when PHP is used as Apache module. You can only use pcntl_fork in CGI mode or from command-line.

Using this function will result in: 'Fatal error: Call to undefined function: pcntl_fork()'
ej <at> wellkeeper dot com
01-Jul-2004 05:56
If you understand what a UNiX fork() command actually does, then the behaviour astrolox describes below is precisely what one would expect. A fork() command creates an identical process (save for the PID) and that includes the TEXT segment, DATA segment, stack, heap, file descriptors, etc.  If you don't want the child to have what's in the buffer, just throw it out (in the child - the parent doesn't need to do anything differently).

  As for his new server that doesn't display the same behaviour, I'm not sure what to say. It would be a mistake for PHP to throw away that buffer for you behind the scenes because someone may well want a child that has access to that buffer. If fork() is properly implemented the *ONLY* thing that is different in the child is that it has it's own PID.
astrolox at lawyersonline dot co dot uk
31-Mar-2004 11:40
When using php 4.3.3, I found that output buffering can really confuse you if you use fork within your script.

The buffer (everything which hasn't been placed on the screen yet) is copied to the child process.

This means that when the child flushes it's buffer, which happens automatically when the script ends, you will get a copy of everything which your code (before the fork) tried to place on to the screen.

This causes it to look like all your code before the fork has run twice, when actually it hasn't.

This doesn't happen on my other server running a newer version of php, but that might be a configuration issue.

Note that using ob_implicit_flush() at the start of the script doesn't appear to solve the problem. Adding ob_end_flush() before the pcntl_fork() command does solve the problem.

Example:
<?
echo "This is an echo before I called the fork command\n";

// uncomment the next line to fix the described problem
#ob_end_flush(); 

$pid = pcntl_fork();
if (
$pid == -1) {
    die(
"could not fork");
} else if (
$pid) {
    echo
"I am the parent, pid = ". $pid ."\n";
} else {
    echo
"I am the child, pid = ". $pid ."\n";
}
?>

Output, before "fixed":

This is an echo before I called the fork command
I am the parent, pid = 15449
This is an echo before I called the fork command
I am the child, pid = 0

Output, after "fixed":

This is an echo before I called the fork command
I am the parent, pid = 15023
I am the child, pid = 0
ben at gelbnet dot com
25-Sep-2002 10:54
I was writing a shell script to get input from a user, however, I needed my script to time out after a certain number of seconds if the user didn't enter enough data. The code below descibes the method I used. It's a little hairy but it does work.

-Ben

#!/home/ben/php/bin/php -q
<?
//GLOBALS
$RETURN_CHAR = "\n";
$TIMEOUT = 5; //number of seconds to timeout on input
$PID = getmypid();
$CHILD_PID = 0;

//Make sure program execution doesn't time out
set_time_limit(0);

function
set_timeout() {
global
$PID;
global
$CHILD_PID;
global
$TIMEOUT;

$CHILD_PID = pcntl_fork();
if(
$CHILD_PID == 0) {
sleep($TIMEOUT);
posix_kill($PID, SIGTERM);
exit;
}
}

function
clear_timeout() {
global
$CHILD_PID;
posix_kill($CHILD_PID, SIGTERM);
}

// read_data()
// gets a line of data from STDIN and returns it
function read_data() {

$in = fopen("php://stdin", "r");
set_timeout();
$in_string = fgets($in, 255);
clear_timeout();
fclose($in);
return
$in_string;
}

// write_data($outstring)
// writes data to STDOUT
function write_data($outstring) {
$out = fopen("php://stdout", "w");
fwrite($out, $outstring);
fclose($out);
}

while(
1) {
write_data("say something->");
$input = read_data();
write_data($RETURN_CHAR.$input);
}

?>
 

 
credits | contact