This article to share the content is the PHP implementation of the system programming of the multi-process programming introduction and orphan process, zombie process, has a certain reference value, the need for friends can refer to
Multi-process programming is also an important aspect of system programming, but PHP programmers often do not need to be concerned with multi-process problems, because Web servers or PHP-FPM have helped us manage process problems, but if we want to use PHP to develop CLI programs, multi-process programming is an essential technology.
The method of process Control in PHP is mainly used in the pcntl extension, so before you do multi-process programming, make sure that your PHP has the latest PCNTL extension installed and can enter php-m command to view the extensions that are currently installed:
This extension provides us with a set of methods for process operations:
The PCNTL function pcntl_alarm-set a alarm alarm signal for the process pcntl_errno-alias pcntl_get_last_errorpcntl_exec-execute the specified program in the current process space pcntl_fork- Produces a branch (child process) at the current position of the current process. Pcntl_get_last_error-retrieve the error number set by the last Pcntl function which failedpcntl_getpriority-get the priority of any process Pcntl_setpriority-Modify the priority of any process pcntl_signal_dispatch-call the processor waiting for the signal pcntl_signal_get_handler-get the current handler for SP Ecified signalpcntl_signal-Install a signal processor pcntl_sigprocmask-set or retrieve a signal waiting for a blocking signal pcntl_sigtimedwait-with a timeout mechanism pcntl_sigwaitinfo- Wait for signal Pcntl_strerror-retrieve The system error message associated with the given errnopcntl_wait-wait or return fork of the child process state Pcntl_wa itpid-the child process state that waits or returns fork pcntl_wexitstatus-returns the return code of an interrupted subprocess pcntl_wifexited-checks whether the status code represents a normal exit. pcntl_wifsignaled-checks if the child process status code represents an interruption due to a signal pcntl_wifstopped-checks whether the child process is currently stopped pcntl_wstopsig-returns a signal that causes the child process to stop Pcntl_wtermsig -Returns the signal that caused the child process to break
pcntl_fork - produces a branch (child process) at the current position of the current process. Fork is the creation of a child process, the parent process and the child process from the position of the fork to continue execution, different from the parent process, the resulting fork return value is the child process number, and the child process gets 0.
The sub-process that is forked out almost completely replicates the parent process, and the parent-child process shares the code snippet, although the data segments, heaps, and stacks of the parent-child process are independent of each other, but at the beginning, the child process completely replicates the data of the parent process, but the subsequent modifications do not affect each other.
int pcntl_fork (void)
Create 5 Child Process Code demos:
<?phpfor ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); The child process is created, and the child process starts here. if ($pid = = 0) { break;//The child process exits the loop because the child process also executes the loop code, or the child process creates its own child process. }} Sleep ($i); The first child process created will sleep 0 seconds, the second will sleep 1s, and so on ... The main process sleeps 5 seconds if ($i < 5) { exit ("No."). ($i + 1). "Child process exits ...". Time (). PHP_EOL);} else{ Exit ("Parent process exits ...".) Time (). PHP_EOL);}
Operation Result:
[Root@localhost process]# PHP process.php 1th child process exited ... 1503322773 2nd child process exits ... 1503322774 3rd child process exits ... 1503322775 4th child process exits ... 1503322776 5th child process exits ... 1503322777 Parent Process exits ... 1503322778
for the Pcntl_fork function, it is important to understand:"Fork is the creation of a child process, the parent process and the child process from the position of the fork to continue to execute, different from the parent process, the resulting fork return value is the child process number, and the sub-process gets 0 "
Modify the code above to not let the process exit, and then use the PS command to view the system status:
<?phpfor ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { break;//The child process exits the loop }}sleep ($i) because the child process also executes the loop code; The first child process created will sleep 0 seconds, the second will sleep 1s, and so on ... The main process sleeps 5 seconds/*if ($i < 5) { exit ("No."). ($i + 1). "Child process exits ...". Time (). PHP_EOL);} else{ Exit ("Parent process exits ...".) Time (). PHP_EOL);} */while (1) { sleep (1); Execution of a dead loop does not exit}
Post-run input Ps-ef | grep PHP View System process
[Root@localhost ~]# Ps-ef | grep phproot 3670 3609 0 21:54 pts/0 00:00:00 php process.phproot 3671 3670 0 21:54 pts/0 00:00:00 php process.phproot 3672 3670 0 21:54 pts/0 00:00:00 php process.phproot 3673 3670 0 21:54 pts/0 00:00:00 php process.phproot 3674 3670 0 21:54 pts/0 00:00:00 PHP process.phproot 3675 3670 0 21:54 pts/0 00:00:00 php process.phproot 3677 3646 0 21:54 pts/1 00:00:00 grep php
You can see 6 php process.php processes, where the second column is the process number, the third column is the parent process number of the process, and you can see that the parent process number of the next five processes is the process number of the first process.
The code child process above and the parent process are executing the same code, there is no way to let the child process and the parent process do different things, the simplest way is to judge, the child process executes the child Process code, the parent process executes the code of the parent process:
<?php$ppid = Posix_getpid (); Record the process number for the parent process for ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { break;//Because the child process also executes the loop code, so the child process exits the loop }}if ($ppid = = Posix_getpid ()) { //parent process while (1 { sleep (1); }} else{ //Sub-process for ($i = 0; $i < $i + +) { echo "subprocess". Posix_getpid (). "Loop $i ... \ n"; Sleep (1);} }
[Root@localhost process]# PHP process.php sub-process 6677 Loop 0 ... Child process 6676 Loop 0 ... Child process 6678 Loop 0 ... Child process 6680 Loop 0 ... Child process 6679 Loop 0 ... Child process 6677 Loop 1 ... Child process 6676 Loop 1 ... Child process 6678 Loop 1 ... Child process 6680 Loop 1 ... Child process 6679 Loop 1 ... Child process 6677 Loop 2 ... Child process 6676 Loop 2 ... Child process 6678 Loop 2 ... Child process 6680 Loop 2 ...
In fact, the parent-child process of the above program executes the same code, only the if branch into the same, and pcntl_exec can let the child process completely out of the influence of the parent process to execute the new program.
pcntl_exec-executing the specified program in the current process space
void Pcntl_exec (String $path [, array $args [, array $envs]]
Path
Path must be an executable binary file path or a script that specifies an executable path header on the first line of the file (such as a Perl script with #!/usr/local/bin/perl in the first line of the file). For more information, please see the EXECVE (2) Manual of your system.
Args
Args is a string array of arguments to pass to the program.
Envs
Envs is an array of strings to pass to the program as an environment variable. This array is the key = value format, and key represents the name of the environment variable to be passed, and value represents the value of the environment variable.
Note that the return value of this method is special: return False When an error occurs, no error is returned, because the pcntl_exec call succeeds, the child process goes to run the new program inherits from the parent process of the code snippet, data segment, heap, stack and other information is all replaced by the new, at this time the Pcntl_ The EXEC function call stack is no longer present, so there is no return. code example:
<?phpfor ($i = 0; $i < 3; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { echo "sub-process PID =". Posix_getpid (). Php_eol; $ret = pcntl_exec ('/bin/ls '); Execute the LS command, where the call succeeds the subprocess will no longer come back to execute any of the following code var_dump ($ret);//The code here will no longer perform }}sleep (5); Sleep for 5 seconds to ensure that the child process finishes executing, after which it says exit ("main process exits ... \ n");
Operation Result:
[Root@localhost process]# php pcntl_exec.php subprocess pid = 6728 sub-process PID = 6729 Sub-process PID = 6727pcntl_exec.phpprocess.phppcntl_ exec.phpprocess.phppcntl_exec.phpprocess.php Main Process Exit ... [Root@localhost process]# lspcntl_exec.php process.php
The above is a simple introduction to the development of PHP multi-process, for the different survival of the sub-process, the concept of the orphan process and the zombie process, in the Linux system, the init process (1th process) is the ancestor of all processes, the other process is either the child process of the process, or the child process child process, Child process of child process of subprocess ..., Linux system can use the Pstree command to view the process tree structure:
In a multi-process program, if the parent process exits before the child process, the child process will be adopted by the INIT process and become a child of the INIT process, which is called the orphan process, and we can modify the above code slightly to demonstrate this situation:
<?php$ppid = Posix_getpid (); Record the process number for the parent process for ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { break;//The child process exits the loop }}if ($ppid = = Posix_getpid ()) { //parent process exits directly because the child process also executes the loop code Its child processes will become orphan processes exit (0);} else{ //Sub-process for ($i = 0; $i < $i + +) { echo "subprocess". Posix_getpid (). "Loop $i ... \ n"; Sleep (1);} }
Run the program, and then view the status of the process:
[Root@localhost ~]# Ps-ef | grep phproot 2903 1 0 12:09 pts/0 00:00:00 php pcntl.fork.phproot 2904 1 0 12:09 pts/0 00:00:00 php pcntl.fork.phproot 2905 1 0 12:09 pts/0 00:00:00 php pcntl.fork.phproot 2906 1 0 12:09 pts/0 00:00:00 php pcntl.fork.phproot 2907 1 0 12:09 pts/0 00:00:00 php pcntl.fork.phproot 2935 2912 0 12:10 pts/1 00:00:00 grep php
You can see that the parent process number of the five child processes is 1, and at this point the console is no longer occupied by the program, the child process to the background to run, the orphan process was adopted by the INIT process mechanism is necessary to implement the daemon described in one of the prerequisites.
Child processes also have a state called a zombie process, the child process at the end is not completely exited, the kernel process table still retains the record of the process, so that the purpose is to allow the parent process to know the exit status of the child process, and the child process is suicide (call exit or code execution complete) or homicide (signaled termination), The parent process can call the Pcntl_wait or Pcntl_waitpid method to reclaim the child process (corpse), free all resources occupied by the child process, and get the child process's exit status, if the parent process does not recycle, the zombie process persists, and if the parent process exits, These zombie processes are taken over by the Init process and are automatically recycled.
For Linux systems, a long-running multi-process program must reclaim the child process because the process resources of the system are limited, and the zombie process reduces the resources available to the system.
The code shows the spawn of the zombie process:
<?php$ppid = Posix_getpid (); Record the process number for the parent process for ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { break;//The child process exits the loop }}if ($ppid = = Posix_getpid ()) { //parent process does not exit and does not reclaim the child process because the child process also executes the loop code While (1) { sleep (1); }} else{ //child process exits, will become zombie process exit ("child process exits $ppid ... \ n");}
View process status after running:
[Root@localhost ~]# Ps-ef | grep phproot 2971 2864 0 14:13 pts/0 00:00:00 php pcntl.fork.phproot 2972 2971 0 14:13 pts/0 00:00:00 [php] <defunct>root 2973 2971 0 14:13 pts/0 00:00:00 [PHP] <defunct >root 2974 2971 0 14:13 pts/0 00:00:00 [php] <defunct>root 2975 2971 0 14:13 pts/0 00:00:00 [php] <defunct>root 2976 2971 0 14:13 pts/0 00:00:00 [PHP] < Defunct>root 2978 2912 0 14:13 pts/1 00:00:00 grep php
Zombie processes are identified with <defunct> (dead, dead), and unless we end the parent process, these zombie processes persist and cannot be killed with the kill command.
PHP's Pcntl extension provides two ways to reclaim child processes for us to invoke:
int pcntl_wait (int & $status [, int $options = 0]) int pcntl_waitpid (int $pid, int & $status [, int $options = 0])
The pcntl_wait function suspends execution of the current process until a child process exits or receives a signal that requires an interrupt to the current process or calls a signal handler function. If a child process has exited (commonly known as a zombie process) when calling this function, this function returns immediately. All system resources used by the child process will be freed.
See the Wait (2) manual for your system for a detailed specification of what wait is working on your system. This function is equivalent to a value of 1 as the parameter PID and there is no options parameter to invoke the Pcntl_waitpid () function.
code example:
<?php$ppid = Posix_getpid (); Record the process number for the parent process for ($i = 0; $i < 5; $i + +) { $pid = Pcntl_fork (); if ($pid = = 0) { break;//The child process exits the loop }}if ($ppid = = Posix_getpid ()) { //parent process recycles the receive process because the child process also executes the Loop code) while (($id = pcntl_wait ($status)) > 0)//pcntl_wait will block if no child process exits { echo "reclaims child process: $id, child process exit status value: $status ... \ n"; } Exit ("Parent process exits $id .... \ n"); When the child process is all over pcntl_wait return -1}else{ //child process exits, it will become a zombie process sleep ($i); Exit ($i); }
Operation Result:
[Root@localhost php]# php pcntl.fork.php recycle subprocess: 3043, child process exit status value: 0 ... reclaim subprocess: 3044, child process exit status value: 256 ... recycle subprocess: 3045, child process exit status value: 512 ... reclaim sub-process: 3046, child process exit status value: 768 ... reclaim subprocess: 3047, child process exit status value: 1024 ... parent process exits-1 ....
This is just a basic introduction to PHP multi-process programming, the following will be combined with the signal, interprocess communication and the Guardian process to do a further introduction, Welcome to follow-up articles.
PHP is the best language in the world that's all:)
Related recommendations:
PHP network socket and IO multiplexing for system programming