SoFunction
Updated on 2025-03-10

PHP multi-process programming summary (recommended)

1. Prepare

Before you start, make sure you are not using the M$ Windows platform (because I don't have Windows). Linux/BSD/Unix should all be fine. After confirming the working environment, let’s see if we all have the PHP modules we need. Open the terminal and enter the following command:

$ php -m

This command checks and prints all currently enabled extensions of PHP and sees whether pcntl and posix are in the output list.

1.1. pcntl

If pcntl cannot be found, it is probably because the extension was not compiled during compilation. If you compile and install PHP like me, you need to recompile and install PHP. Remember to add --enable-pcntl parameter when configuring.

$ cd /path/to/php_source_code_dir 
$ ./configure [some other options] --enable-pcntl
$ make && make install

1.2. posix

This product will usually be installed by default, as long as you do not add --disable-posix when compiling.

2. Preparation knowledge

Before you proceed, you also need to have a little understanding of Linux multiprocessing. What's going on with multiple processes? This is a little different from the shadow clone in Naruto. First, Naruto grew up to being older, like 16 years old, cough. One day he activated his shadow clone and divided five of him. Obviously, these clones are also 16-year-old Naruto, not babies who don’t know anything when they are born (that’s called clones). Then, a different place comes: the clones become independent people and do their own things, no longer knowing what the other clones and original bodies have done (of course, they will not accumulate experience for the original bodies like in cartoons). Unless they communicate with each other, only what happened before the age of 16 is their common memory.

Some classmate said, "Boss, aren't you cheating on me?" I haven't seen Naruto! Then you can go and see it...

Finally, after finishing the preparatory knowledge, we will roughly understand what the child process is like when it comes to the main process. The code of the child process is exactly the same as the main process, and there is also a part of the same thing that is all the content that is executed until the shadow clone is started. For details, please refer to the "Operating System" course.

3. Shadow clone technique

So, how can you understand the contents in the scroll without some basic knowledge? When I opened the scroll, I first saw a word: fork.

3.1. fork

fork? The forks are forked, one becomes multiple! That's about that. Use this command to create a child process. Here you need to use the pcntl_fork() function. (You can take a brief look at the introduction of this function in the PHP manual.) Create a PHP script:

$pid = pcntl_fork(); // Once the call is successful, things become a little differentif ($pid == -1) {
  die('fork failed');
} else if ($pid == 0) {
} else {
}

The pcntl_fork() function creates a child process. The only difference between the child process and the parent process is that the PID (process ID) and PPID (parent process ID). Use the ps command to view the process in the terminal (ask man how to use ps: man ps). When the function returns a value of -1, it means that fork has failed. Try adding a sentence before if: echo $pid . PHP_EOL;. Run your script and the output may look like the following (the result shows that the code of the child and the parent process is the same):

67789 # This is printed by the parent process0   # This is printed by the child process

After the pcntl_fork() function is called successfully, the PID of the child process will be returned in the parent process, while the 0 is returned in the child process. Therefore, the following is to directly use the if branch to control the parent process and the child process to do different things.

3.2. Assign tasks

Then let’s talk about Naruto’s shadow clone when he was 16 years old, and assign two simple output tasks to the original body and clone:

$parentPid = getmypid(); // This is the legendary memory before the age of 16$pid = pcntl_fork(); // Once the call is successful, things become a little differentif ($pid == -1) {
  die('fork failed');
} else if ($pid == 0) {
  $mypid = getmypid(); // Use getmypid() function to get the PID of the current process  echo 'I am child process. My PID is ' . $mypid . ' and my father\'s PID is ' .$parentPid . PHP_EOL;
} else {
  echo 'Oh my god! I am a father now! My child\'s PID is ' . $pid . ' and mine is '. $parentPid . PHP_EOL;
}

The output might be like this:

Oh my god! I am a father now! My child's PID is 68066 and mine is 68065
I am child process. My PID is 68066 and my father's PID is 68065

To emphasize again, after the call of pcntl_fork() is successful, one program becomes two programs: the $pid variable value obtained by one program is 0, which is the child process; the $pid value obtained by the other program is greater than 0, which is the PID of the child process, which is the parent process. In the following branch statement, different codes are run due to the different values ​​of $pid. Let me emphasize again: the code of the child process is the same as that of the parent process. Therefore, they have to assign different tasks to them through branch statements.

3.3. Subprocess recycling

Did you have a man ps just now? Generally, I am used to using ps aux plus grep command to find running background processes. There is a column of STATs that identifies the running status of each process. Here, we focus on state Z: Zombie. When the child process exits before the parent process and the parent process does not handle it, the child process will become a zombie process. Oops is different from the shadow clone in Naruto. Naruto's shadow clone disappears automatically after being fucked to death, but if the child process clone dies, there is still an empty shell left until the parent process recycles it. Although the zombie process does not occupy much memory, it is very annoying. The pile of zombies lying in the yard feels strange. (Don't forget that they also occupy PID)

Generally speaking, the child process that has been cancelled before the parent process ends. There is a pcntl_wait() function inside the pcntl extension, which will hang the parent process until a child process exits. If a child process becomes a zombie, it will return immediately. All child processes need to be recycled, so it doesn’t matter if you wait too much!

3.4. The parent process hangs first

What if the parent process hangs first? what happens? Nothing will happen, and the child process is still running. But at this time, the child process will be handed over to process No. 1, and process No. 1 becomes the stepfather of these child processes. Process 1 will handle the resources of these processes well, and when they end, process 1 will automatically recycle resources. So, another temporary way to deal with zombie processes is to close their parent processes.

4. Signal

Generally, multi-process matters are finished, but signals are indeed a very important thing in the system. A signal is a signal light. When a signal light is turned on, the program will react. You must have used this. For example, if you run a program in the terminal, you will not react after waiting for a long time. Maybe you will press Ctrl+C to close the program. In fact, here is a interrupt signal sent to the program through the keyboard: SIGINT. Sometimes, if the process loses its response, it will execute the kill [PID] command. If no other parameters are added, the program will receive a SIGTERM signal. When the program receives the above two signals, the execution will end by default. So is it possible to change this default behavior? It must be possible!

4.1. Register signal

Humans are alive programs, but programs need to follow the rules set by humans to operate. Now start to reset the rules for the signal. The function used here is pcntl_signal() (why don’t you check the PHP manual first before continuing?). The following program will redefine the behavior for SIGINT, be optimistic:

// Define a processor, and only output one line of information after receiving the SIGINT signalfunction signalHandler($signal) {
  if ($signal == SIGINT) {
    echo 'signal received' . PHP_EOL;
  }
}
// Signal registration: When a SIGINT signal is received, the signalHandler() function is calledpcntl_signal(SIGINT, 'signalHandler');
while (true) {
  sleep(1);
  // do something
  pcntl_signal_dispatch(); // When receiving the signal, call the registered signalHandler()}

Execute it and press Ctrl+C at any time to see what will happen.

4.2. Signal distribution

Let me explain: the pcntl_signal() function is just a registered signal and its processing method. The one that actually receives the signal and calls its processing method is the pcntl_signal_dispatch() function. Try replacing // do something with the following code:

for ($i = 0; $i < 1000000; $i++) {
  echo $i . PHP_EOL;
  usleep(100000);
}

Execute this script in the terminal, and try to press Ctrl+C when it keeps outputting numbers. See what the program responds? Well... there is nothing, except that there may be an extra ^C on the screen, the program keeps outputting numbers. Because the program has not been executed to pcntl_signal_dispatch(), signalHandler() is not called, so signal received is not output.

4.3. Version issues

If you read the PHP documentation carefully, you will find that the function pcntl_signal_dispatch() is supported only by PHP 5.3 or above. If your PHP version is greater than 5.3, it is recommended to use this method to call the signal processor. Versions below 5.3 need to add a sentence before registering the signal: declare(ticks = 1); means that every time a low-level instruction is executed, the signal is checked. If a registered signal is detected, its signal processor will be called. It’s very unhappy to think about it, why do you keep checking? Just check it out at the place we designated.

4.4. Feel the zombie process

Now we go back to the problem of child process recycling (I almost forgot = ="). When one of your child processes has hangs (or ends), but the parent process is still running and may not exit for a long time. A zombie process has stood up from then on! At this time, the Umbrella Company (kernel) found a zombie appeared in its territory. Whose son is this zombie? Just look at PPID and you will know. Then, the kernel sends a signal to the PPID process (that is, the parent process of the zombie process): SIGCHLD. Then, do you know how to recycle this child process in the parent process? Tip, use the pcntl_wait() function.

4.5. Send a signal

I hope I have just passed the kill order seriously. It is actually sending signals to the process. In PHP, you can also call the posix_kill() function to achieve the same effect. With it, you can control the operation of other children in the parent process. For example, when closing all child processes before the parent process ends, then when fork, record the PIDs of all child processes in the parent process, and send the end signal to the child process in turn before the parent process ends.

5. Practice

PHP's multi-process is quite similar to C. After understanding it, I will write in other languages ​​in the future. This is almost the same. If you have time, try writing a small program and experience it yourself:

1.16-year-old Naruto sent a shadow clone and divided five clones

2. Each clone survives randomly for 10 to 30 seconds, and what outputs every second

3. Ensure that the original body can feel the end of the clone, and then start another clone to ensure that there are up to 5 clones.

4. Do not use nohup to allow the original body to run after the terminal is closed.

5. Write the number of clones (5) into a configuration file. When sending a signal to the original body (you can consider using SIGUSR1 or SIGUSR2), the original body reads the configuration file and updates the maximum number of clones allowed.

6. If there are too many clones, close a few; if there are too few, divide a few more

hint:

1. Use while loop to ensure the process runs, pay attention to sleep to avoid 100% CPU usage
2. When the terminal running the process is closed, the program will receive a SIGHUP signal.
3. You can use the parse_ini_file() function to parse the INI configuration file

The above PHP multi-process programming summary (recommended) is all the content I share with you. I hope you can give you a reference and I hope you can support me more.