note 99350 modified in function.pcntl-fork by danbrown
| From: | danbrown@php.net | Date: | Thu, 19 Aug 2010 16:44:49 +0000 |
| Subject: | note 99350 modified in function.pcntl-fork by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-171861@lists.php.net to get a copy of this message | ||
you should be _very_ careful with using fork in scripts beyond academic examples,
or rather just avoid it alltogether, unless you are very aware of it's limitations.
the problem is that it just forks the whole php process, including not only
the state of the script, but also the internal state of any extensions loaded.
this means that all memory is copied, but all file descriptors are shared among
the parent and child processes.
and that can cause major havoc if some extension internally maintains
file descriptors.
the primary example is ofcourse mysql, but this could be any extensions that
maintains open files or network sockets.
also, just reopening your connection in the parent or child isn't a safe
method, because when the old connection resource is destroyed, the extension
might not just close it, but for example send a request to the server to log
off, making the connection unusable.
this happens with mysql for example, when php exits - in the following script the query will always
fail with "MySQL server has gone away":
<?php
mysql_connect(/* enter a working server here maybe? */);
if(pcntl_fork()) die(); // fork a child and have the parent terminate
//if(pcntl_fork()) posix_kill(getmypid(),9); // works, but very ugly
$r=mysql_query("select 1;");
if(!$r)die(mysql_error()."\n");
?>
(it was suggested that processes kill themselves with SIGKILL to avoid any cleanup on shutdown)
(the only save way would be to close all connections and reopen them after the fork, and even that
might not be possible if an extension keeps one open internally)
for a nice demonstration of the havoc fork can create, try the below script.
it opens a mysql connection, then forks, and runs queries from both parent and child,
verifying that it receives the correct result.
run it (on the cli preferably) a few times, and you will find various possible
results:
- very often is just hangs and doesn't output anything anymore
- also very often, the server closes the connection, probably because it
receives interleaved requests it can't process.
- sometimes one process gets the result of the OTHER processes'
query! (because both send their queries down the same socket,
and it's pure luck who gets the reply)
<?php
mysql_connect(/* enter a working server here maybe? */);
$f=pcntl_fork();
while(true){
sleep(rand(0,10)/100);
$r=mysql_query("select $f;");
if(!$r)die($f.": ".mysql_error()."\n");
list($x)=mysql_fetch_array($r);
echo ($f)?".":"-";
if($x!=$f) echo ($f.": fail: $x!=$f\n ");
}
?>
--was--
you should be _very_ careful with using fork in scripts beyond academic examples,
or rather just avoid it alltogether, unless you are very aware of it's limitations.
the problem is that it just forks the whole php process, including not only
the state of the script, but also the internal state of any extensions loaded.
this means that all memory is copied, but all file descriptors are shared among
the parent and child processes.
and that can cause major havoc if some extension internally maintains
file descriptors.
the primary example is ofcourse mysql, but this could be any extensions that
maintains open files or network sockets.
also, just reopening your connection in the parent or child isn't a safe
method, because when the old connection resource is destroyed, the extension
might not just close it, but for example send a request to the server to log
off, making the connection unusable.
this happens with mysql for example, when php exits - in the following script the query will always
fail with "MySQL server has gone away":
<?
mysql_connect(/* enter a working server here maybe? */);
if(pcntl_fork()) die(); // fork a child and have the parent terminate
//if(pcntl_fork()) posix_kill(getmypid(),9); // works, but very ugly
$r=mysql_query("select 1;");
if(!$r)die(mysql_error()."\n");
?>
(it was suggested below that processes kill themselves with SIGKILL to avoid any cleanup on
shutdown)
(the only save way would be to close all connections and reopen them after the fork, and even that
might not be possible if an extension keeps one open internally)
for a nice demonstration of the havoc fork can create, try the below script.
it opens a mysql connection, then forks, and runs queries from both parent and child,
verifying that it receives the correct result.
run it (on the cli preferably) a few times, and you will find various possible
results:
- very often is just hangs and doesn't output anything anymore
- also very often, the server closes the connection, probably because it
receives interleaved requests it can't process.
- sometimes one process gets the result of the OTHER processes'
query! (because both send their queries down the same socket,
and it's pure luck who gets the reply)
<?
mysql_connect(/* enter a working server here maybe? */);
$f=pcntl_fork();
while(true){
sleep(rand(0,10)/100);
$r=mysql_query("select $f;");
if(!$r)die($f.": ".mysql_error()."\n");
list($x)=mysql_fetch_array($r);
echo ($f)?".":"-";
if($x!=$f) echo ($f.": fail: $x!=$f\n ");
}
?>
http://php.net/manual/en/function.pcntl-fork.php