PHP multi process programming example

  • 2021-07-22 09:12:19
  • OfStack

Envy Naruto's shadow doppelganger in Naruto? Yes, the PHP program can start the shadow doppelganger! If you want to complete the task and feel that one process is too slow, try to do it with multiple processes. This article will introduce the basic requirements of PHP multi-process under 1, how to create multi-process and basic signal control, and will not tell you how to communicate and share information between processes for the time being.

Step 1 Prepare

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


$ php -m

This command checks and prints all the current PHP extensions that are open to see if pcntl and posix are in the output list.

1.1. pcntl

If you can't find pcntl, 80% of you didn't compile this extension when compiling. If you and I are compiling and installing PHP, you need to recompile and install PHP. Remember to add-enable-pcntl parameters when configuring.


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

1.2. posix

This product will be loaded by default, as long as you don't add-disable-posix when compiling.

2. Preliminary knowledge

Before continuing, you need to know one more thing about Linux multi-process. What about multi-process? This is a little different from the shadow doppelganger in Naruto. First of all, Naruto grew up from childhood to adulthood, for example, 16 years old, cough. One day, he started the shadow doppelganger and separated five of him. Apparently, these doppelganger are also 16-year-old Naruto, not babies who cry when they are born without knowing anything (that's called cloning). Then, a different place came: the doppelganger became independent people to do their own things, and they no longer knew what other doppelganger and the original did (of course, they wouldn't accumulate experience for the original as in the cartoon). Unless they communicate with each other, only things before the age of 16 are their common memories.

Some students said, boss, don't you cheat your father? I haven't seen Naruto! Then go and see it once...

Finally, the preparatory knowledge is finished, that is, to roughly understand what is going on with the sub-process of the main process. The code of the sub-process and the main process are exactly the same, and there are 1 part and 1 kind of things that are all the contents executed until the shadow doppelganger is launched.

3. Shadow doppelganger

So, how can you understand the contents of the scroll without some basic knowledge? When you open the scroll, you first see one word: fork.

3.1. fork

Fork? Forks are bifurcated, one becomes more! That's about what it means. This command is used to create child processes. The pcntl_fork () function is needed here. (You can simply look at the introduction of this function in the PHP manual.) Create an PHP script:


$pid = pcntl_fork(); // 1 Once the call is successful, things become a little different
if ($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 PID (process ID) and PPID (parent process ID) are different. Use the ps command to view the process under the terminal (ask man to see how ps works: man ps). When the return value of the function is-1, it means that fork failed. Try adding a sentence before if: echo $pid. PHP_EOL; . Run your script, and the output may look like this (the result shows that the code of the child process and the parent process is the same):

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

When the pcntl_fork () function is called successfully, PID of the child process is returned in the parent process, and 0 is returned in the child process. Therefore, the if branch is directly used to control the parent process and child process to do different things.

3.2. Assignment of Tasks

Then let's talk about Naruto's 16-year-old shadow doppelganger, and assign two simple output tasks to the original body and doppelganger:


$parentPid = getmypid(); // This is the legend 16 Memories before the age of
$pid = pcntl_fork(); // 1 Once the call is successful, things become a little different
if ($pid == -1) {
    die('fork failed');
} else if ($pid == 0) {
    $mypid = getmypid(); // Use getmypid() Function to get the PID
    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 look 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

Again, after the successful call of pcntl_fork (), one program becomes two programs: the value of $pid variable obtained by one program is 0, which is a child process; Another program gets a value of $pid greater than 0, which is the PID of the child process, which is the parent process. In the following branch statement, different code is run due to the different value of $pid. Re-emphasize 1: the code of the child process and the code of the parent process are 1. Therefore, they should be assigned different tasks through branch statements.

3.3. Child Process Recycling

Did you just have man ps? I am used to using ps aux plus grep commands to find running daemons. There is a column of STAT, which identifies the running status of each process. Here, we focus on the status Z: Zombie (Zombie). When the child process exits before the parent process and the parent process does nothing to it, the child process will become a zombie process. Oops is different from the shadow doppelganger in Huoying. Naruto's shadow doppelganger is dry dead after the automatic disappearance, but here the child process doppelganger dead words still have a shell in, until the parent process recycle it. Zombie process although does not occupy what memory, but very eyesore, how a pile of zombies lying in the yard feel strange. (Don't forget that they also occupy PID.)

1 Generally speaking, it is enough to recycle the dead child process before the parent process ends. Within the pcntl extension there is an pcntl_wait () function that suspends the parent process until one child process exits. If a child process becomes a zombie, it will return immediately. All child processes have to be recycled, so it doesn't matter if you wait!

3.4. The parent process hangs first

What if the parent process hangs up first? What will happen? Nothing will happen, and the child process is still running. But at this time, the child process is handed over to the No.1 process, and the No.1 process becomes the stepfather of these child processes. Process 1 handles the resources of these processes well, and when they end, Process 1 automatically recycles the resources. Therefore, another temporary way to deal with zombie processes is to shut down their parent process.

Step 4 Signals

As many as 1 process things mentioned above is finished, but the signal is really a very important thing in the system. A signal is a signal lamp. When a signal lamp is lit, the program will respond. You must have used this one, for example, running a program under the terminal, and waiting for half a day has no reaction. Maybe you will press Ctrl + C to close this program. In fact, this is an interrupt signal sent to the program through the keyboard: SIGINT. Sometimes the process loses its response and executes the kill [PID] command. Without adding any other parameters, the program will receive an SIGTERM signal. When the program receives the above two signals, it will end by default. Is it possible to change this default behavior? Must be able to!

4.1. Registration signal

People are alive and programs are alive, but programs need to follow the rules made by people to run. Now start to reset the rules for the signal. The function used here is pcntl_signal () (why not check the PHP manual before continuing?) . The following program will redefine the behavior of SIGINT, pay attention to it:


// Definition 1 Processors, received SIGINT Output only after the signal 1 Row information
function signalHandler($signal) {
    if ($signal == SIGINT) {
        echo 'signal received' . PHP_EOL;
    }
}
// Signal registration: When received SIGINT Signal, call the signalHandler() Function
pcntl_signal(SIGINT, 'signalHandler');
while (true) {
    sleep(1);
    // do something
    pcntl_signal_dispatch(); // When a signal is received, the registered signalHandler()
}

Execute 1 and press Ctrl+C at any time to see what happens.

4.2. Signal Distribution

Description 1 below: pcntl_signal () function is only to register the signal and its processing method, really receive the signal and call its processing method is 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 under the terminal and try to press Ctrl+C while it keeps outputting numbers. See what the program responds to. Well... nothing, except that there may be an extra C on the screen, program 1 keeps outputting numbers. Because Program 1 does not execute to pcntl_signal_dispatch (), signalHandler () is not called, so signal received is not output.

4.3. Version issues

If you look at the PHP documentation carefully, you will find that the function pcntl_signal_dispatch () is supported only after PHP 5.3. If your PHP version is greater than 5.3, it is recommended to use this method to call the signal processor. 5.3 The following versions need to add a sentence before the registration signal: declare (ticks = 1); It means that every time a low-level instruction is executed, the signal is checked once, and if a registered signal is detected, its signal processor is called. It's annoying to think about it. Why do you check it all the time? Just check it at the place we designated.

4.4. Feel the zombie process

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

4.5. Send a signal

I hope there has just been a serious man over kill command. It simply signals the process, and the posix_kill () function can be called in PHP to do the same. With it, you can control the operation of other child processes in the parent process. For example, when closing all child processes before the end of the parent process, fork records PID of all child processes in the parent process, and sends end signals to the child processes in turn before the end of the parent process.

5. Practice

PHP's multi-process and C is quite similar, after understanding the words written in other languages are similar, almost all of them are such a situation. If you are free, try to write a small program and experience the next taste:

1.16-year-old Naruto sent a shadow doppelganger and separated five doppelganger
2. Each doppelganger lives randomly for 10 to 30 seconds, and what does it output every second
3. Ensure that the original body can feel the end of the doppelganger, and then start another doppelganger, and ensure that there are up to 5 doppelganger
4. Do not use nohup, so that the original can still run after the terminal is shut down
5. Write the number of doppelganger (5) into a configuration file. When sending a signal to the original (SIGUSR1 or SIGUSR2 can be considered), the original reads the configuration file and updates the maximum number of doppelganger allowed
6. If there are more doppelganger, close a few; If there are fewer, separate a few more

Hint:

1. Use while loop to ensure that the process runs, and pay attention to sleep to avoid 100% CPU occupation
2. When the terminal running the process is closed, the program will receive an SIGHUP signal
3. The INI configuration file can be parsed with the parse_ini_file () function


Related articles: