僵尸进程:当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。
孤儿进程:是指其父进程执行完成或被终止后仍继续运行的一类进程。这些孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
守护进程:在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。
PHP多进程需要安装pcntl扩展。pcntl是php官方的多进程扩展,只能在linux环境使用。
阻塞方式:
//阻塞方式:父进程在pcntl_wait()将自己阻塞,等待子进程运行完了才接着运行。
$str = "hello, world" . PHP_EOL;
echo $str; //下面的代码,将会被主进程和子进程共同执行
for ($i=0; $i<2; $i++) {
$pid = pcntl_fork(); //创建一个子进程。这个函数,在主进程中返回子进程进程id,在子进程返回0,开启失败在主进程返回-1。上面的变量内存将会复制一份到子进程中。
if ($pid > 0) { //主进程代码
//父进程获取自己的进程id
echo "parent->pid = ", getmypid(), PHP_EOL;
pcntl_wait($status); //等待进程结束,然后回收已经结束的进程(等待子进程中断,防止子进程成为僵尸进程)
} else if ($pid == 0) { //子进程代码
//子进程获取自己的进程id
echo "child->pid = ", getmypid(), PHP_EOL;
exit; //子进程执行完自己的任务后,退出
} else { //创建失败
echo "创建子进程失败", PHP_EOL;
break;
}
}
非阻塞方式:
//非阻塞方式:父进程可以回收已经结束的子进程,又可以并行
declare (ticks = 1);
pcntl_signal(SIGCHLD, 'garbage');
echo "***** parent start, pid = ", getmypid(), " *****", PHP_EOL;
for ($i=0; $i<2; $i++) {
$pid = pcntl_fork(); //创建一个子进程
if ($pid > 0) { //主进程代码
//父进程获取自己的进程id
echo "parent->pid = ", getmypid(), PHP_EOL;
sleep(5);
} else if ($pid == 0) { //子进程代码
//子进程获取自己的进程id
echo "child->pid = ", getmypid(), PHP_EOL;
sleep(2);
exit(0); //子进程执行完自己的任务后,退出
} else { //创建失败
echo "创建子进程失败", PHP_EOL;
break;
}
}
//垃圾回收
function garbage($signal){
echo "signal $signal received", PHP_EOL;
while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) {
echo "child end, pid = $pid, status = $status", PHP_EOL;
}
}
非阻塞方式:
//非阻塞方式:父进程可以回收已经结束的子进程,又可以并行
pcntl_signal(SIGCHLD, function($signal){
echo "signal $signal received", PHP_EOL;
while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) {
echo "child end, pid = $pid, status = $status", PHP_EOL;
}
});
echo "***** parent start, pid = ", getmypid(), " *****", PHP_EOL;
for ($i=0; $i<2; $i++) {
$pid = pcntl_fork(); //创建一个子进程
if ($pid > 0) { //主进程代码
//父进程获取自己的进程id
echo "parent->pid = ", getmypid(), PHP_EOL;
sleep(5);
} else if ($pid == 0) { //子进程代码
//子进程获取自己的进程id
echo "child->pid = ", getmypid(), PHP_EOL;
sleep(2);
exit(0); //子进程执行完自己的任务后,退出
} else { //创建失败
echo "创建子进程失败", PHP_EOL;
break;
}
}
pcntl_signal_dispatch();
非阻塞方式:
//非阻塞方式
for ($i=0; $i<2; $i++) {
$pid = pcntl_fork(); //创建一个子进程
if ($pid > 0) { //主进程代码
//父进程获取自己的进程id
echo "parent->pid = ", getmypid(), PHP_EOL;
sleep(5);
} else if ($pid == 0) { //子进程代码
//子进程获取自己的进程id
echo "child->pid = ", getmypid(), PHP_EOL;
sleep(2);
exit(0); //子进程执行完自己的任务后,退出
} else { //创建失败
echo "创建子进程失败", PHP_EOL;
break;
}
}
//等待子进程执行结束
while (pcntl_waitpid(0, $status) != -1) {
$status = pcntl_wexitstatus($status);
echo "child end, status = $status", PHP_EOL;
}