I am trying to use a pcntl extetntion for PHP to run some methods of my CLI class in a new thread. I wrote a small test method:
private function startProcess($data)
{
$this->log('Start a child process');
$pid = pcntl_fork();
if($pid == -1)
$this->log('Could not fork');
elseif($pid)
pcntl_wait($status);
else {
$this->process($data);
sleep(10);
posix_kill(posix_setsid(), SIGTERM);
}
}
This method is called 10 times. $this->process($data); just prints the data in the console. As i understood it should start 10 processes and print my data, after it exit. But instead i get to wait 10 seconds for each message. Where i'm wrong?
You are waiting for each process to complete immediately after starting it. If you really want to run 10 at a time, don't wait until you started all 10.
for($i = 0; $i < 10; $i++)
startProcess(...);
for($i = 0; $i < 10; $i++)
pcntl_wait($status);
private function startProcess($data)
{
$this->log('Start a child process');
$pid = pcntl_fork();
if($pid == -1)
$this->log('Could not fork');
elseif(!$pid) {
$this->process($data);
sleep(10);
posix_kill(posix_setsid(), SIGTERM);
}
}
Related
I am running this via the command line. When the loop is running, is there any way I can pause the execution of the code? Ideal case would be that I could press a key to pause and then another key to resume. If I don't press the pause key then the loop continues until $i == 1000
<?php
echo "How long should the code sleep between increments?\n";
echo ">> ";
$sleep = trim(fgets(STDIN));
for ($i = 1; $i <= 1000; $i++) {
echo "$i\n";
sleep($sleep);
}
This is a heavily simplified example of my actual need for the code.
I don't sure my code is best solution or not but it work.
function checkResume()
{
$r = false;
while (!$r) {
if (fgets(STDIN) == "r") {
$r = true;
}
}
}
function checkPause()
{
$input = fgets(STDIN);
if (!empty($input) && $input == "p") {
return true;
}
return false;
}
echo "How long should the code sleep between increments?\n";
echo ">> ";
$sleep = trim(fgets(STDIN));
echo "\nStart ...\n";
stream_set_blocking(STDIN, false);
for ($i = 1; $i <= 1000; $i++) {
if (checkPause()) {
echo "wait for resume \n";
checkResume();
}
echo "$i\n";
sleep($sleep);
}
Hope this help.
I'm starting 10 processes asynchronously:
$procs = [];
for($i = 0; $i < 10; $i++) {
$proc = new Process('ls -lsa');
$proc->start();
$procs[$i] = $proc;
}
Now i want to wait asynchronous for every process to finish and print out state informations while waiting:
foreach($procs as $proc) {
$proc->wait(function ($type, $buffer) {
if (Process::ERR === $type) {
// Print out error ...
} else {
// Print out state informations ...
});
}
}
The Problem is at the wait function. It waits for the task to finish and then go on to the next tasks. But i want this to run asynchronous.
How can i do this?
Thanks !
As per the Symfony docs the wait method is blocking and therefore will wait until that process is finished before continuing.
If you don't want to wait you could refactor your code to use the run method:
for($i = 0; $i < 10; $i++) {
$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
$procs[$i] = $proc;
}
I need to write code which meets few conditions:
Is an infinity loop
After 4 forks, goes to sleep for 5 seconds.
When in child process, execute things.
When in parent process, fork again.
When it returns -1, catch exception.
So here's what I've written so far:
while(true) {
for ($i = 1; $i <= 4; ++$i) {
$pid = pcntl_fork();
if($pid == 0){
//execute stuff
} else if ($pid == -1){
//error
} else if($pid > 0) {
//fork again?
}
}
sleep(5);
}
But I feel like this is just plain wrong. Also I have no idea how to fork again in parent. How this should look like?
I am trying to start a child process from parent when its terminated normally or due to an error.Using pcntl_waitpid, It become possible to get status from child. By that status I want restart the same script or process again. Here is an example.
<?php
for ($i = 1; $i <= 5; ++$i) {
$pid = pcntl_fork();
if (!$pid) {
sleep(1);
print "In child $i\n";
exit($i);
}
}
while (pcntl_waitpid(0, $status) != -1) {
$status = pcntl_wexitstatus($status);
echo "Child $status completed\n";
}
?>
How can it possible? Thanks in advance.
Try
echo $i;
break;
instead
exit($i);
I have been using the script below, however, I want it to ping 3-4 times, and within that 3-4 times if it has even a single request timeout, I want php to come back as failed.
Here's a script I'm using:
<?php
function pingAddressHasNeverFailed($tries) {
for ($i = 0; $i < $tries; $i++) {
$pingresult = shell_exec("ping -c 1 www.google.com", $outcome, $status);
if ($status != 0)
return false;
}
return true;
}
if (pingAddressHasNeverFailed(3)) {
echo "uoc gi";
}
?>
Please help if you can, thank you so much in advance!
If any ping fails (in a set) it will not have 0% in the output (i.e. 0% packet loss), which is the same for Linux and Windows:
function ping($host, $times = 3)
{
exec("/bin/ping -c 3 $host", $out, $status);
return $status === 0 && false !== strpos(join('', $out), '0%');
}
if (ping('www.google.com)) {
echo "yay\n";
} else {
echo "oh dear\n";
}
You may have to adjust the ping arguments to fit your environment and make sure that the host name is sanitized.
In that case you'll need to execute command n (n is a number of tries) times. E.g.:
function pingAddressHasNeverFailed($tries) {
$outcome = array();
$status = -1;
for ($i = 0; $i < $tries; $i++) {
$pingresult = exec("/bin/ping -n 1 www.google.com", $outcome, $status);
if ($status != 0)
return false;
}
return true;
}
Usage:
if (pingAddressHasNeverFailed(3)) {
//do something useful
}