Tuesday, June 15, 2010
青木瓜泡茶 痛風不見了 治療尿酸效果更佳
Monday, June 14, 2010
[Backup for peronal reference]
Process Forking with PHP
Posted March 4th, 2004 in PHP
Unix supports the process of forking which allows a parent process to spawn a subprocess and continue running both processes concurrently. It is possible to do this in PHP using the PHP Process Control Functions. Note that you should never attempt to use these process control forking functions when using a webserver; you shuld only fork applications when using the PHP command line client.
Before you can use the PHP process control functions you must compile the PCNTL extensions into PHP using the --enable-pcntl
configure option (ie ./configure --enable-pcntl
along with all the other configuration options you would like to compile into the PHP binary). No additional libraries need to be pre-installed. Note that these process control extensions will not work on non-Unix platforms (ie Microsoft Windows).
Basic Forking Example
A very basic and commonly used example for forking a process in PHP is as follows:
$pid = pcntl_fork();
if($pid) {
// parent process runs what is here
print "parent\n";
}
else {
// child process runs what is here
print "child\n";
}
Running this will output the following:
child
parent
Child process is a copy of the parent process
What actually happens when you call the pcntl_fork()
function is that a child process is spawned which is exactly the same as the parent process and continues processing from the line below the function call. All variables and objects etc are copied into the child process as-is but these are new copies which belong to the new process. Modifying them in the child process does not affect the values in the parent (or any other forked) process.
The parent process will have a value assigned to $pid
whereas the child process will not, hence the if
test. Note that in the above example, both processes would continue running whatever code is after the if statement, something which is rarely mentioned in examples of PHP process forking on the web.
To illustrate this, we'll modify the example above slightly to add additional output as follows:
$pid = pcntl_fork();
print "start\n";
if($pid) {
// parent process runs what is here
print "parent\n";
}
else {
// child process runs what is here
print "child\n";
}
print "end\n";
Running this will display the following:
start
child
end
start
parent
end
Making the parent process wait until the child has finished
So ideally you want to let either the child or parent continue processing the rest of the script and make the other process exit after the process is forked. If you exit from the parent process, however, you'll end up with "zombie" processes running which do not belong to any process. Therefore the parent process needs to wait until all the child processes have finished running before exiting itself. You can do this using the pcntl_waitpid()
function, which will cause the parent process to wait until the child process has completed. You can then either just let the parent process exit, or do any tidy up code that is required.
An example of doing this is as follows:
$pid = pcntl_fork();
if($pid) {
// this is the parent process
// wait until the child has finished processing then end the script
pcntl_waitpid($pid, $status, WUNTRACED);
exit;
}
// the child process runs its stuff here and then ends
...
The exit
call in the parent process ensures that processing stops at that point and the parent does not execute any of the code intended for the child. Another way of doing the same thing without the exit code would be as follows:
$pid = pcntl_fork();
if($pid) {
// this is the parent process
// wait until the child has finished processing then end the script
pcntl_waitpid($pid, $status, WUNTRACED);
}
else {
// the child process runs its stuff here
}
Exit codes from the child process
You could optionally have an exit
call at the end of the child part of the if
statement.
The $status
parameter passed to pcntl_waitpid()
stores the return value from the child process. If the child process returns 0 (ie success) then it will also be zero. On my Linux desktop the value returned as $status
would be the value returned from the exit call multipled by 256. So if the child process ended with exit(2)
my system returned 512 as the $status
value. Whether this is the same across all Unix systems I do not know.
Getting the parent process to wait until the child process has completed is useful for then doing something else based on the return value of the child process as shown in the following example:
$pid = pcntl_fork();
if($pid) {
// this is the parent process
// wait until the child has finished processing then end the script
pcntl_waitpid($pid, $status, WUNTRACED);
if($status > 0) {
// an error occurred so do some processing to deal with it
}
}
else {
// the child process runs its stuff here
...
if(...successful condition...) {
exit(0); // this indicates success
}
else {
exit(1); // this indicates failure
}
}
Forking multiple child processes
This final example illustrates how you could fork several children from the parent process with PHP. The loop runs three times and forks a child process for each loop, storing the child pids into an array. After running the stuff for the child process the child then exits. A second loop runs in the parent after the first to ensure all child processes have finished running before resuming its own process.
Note it is very important in this sort of process that the child explicitly exits in its section of the script, otherwise each child will continue running through the first, and then second, loop.
$pids = array();
for($i = 0; $i < 3; $i++) {
$pids[$i] = pcntl_fork();
if(!$pids[$i]) {
// child process
...
exit();
}
}
for($i = 0; $i < 3; $i++) {
pcntl_waitpid($pids[$i], $status, WUNTRACED);
}
// complete parent processing now all children have finished
...
The PHP manual pages for process control functions can be found at www.php.net/manual/en/ref.pcntl.php. There are a number of user contributed notes for each of the functions which should also help with your understanding of process forking in PHP.