Processes and Interprocess Communication in PHP | PHP Interview Questions

By | August 17, 2021
 

I. Introduction

A process is a running activity of a program with independent functions on a certain set of data. In other words, when the system schedules multiple CPUs, the basic unit of a program. Process is not an unfamiliar concept to most languages, as the world’s best language PHP" is certainly an exception.

2. Environment

The process in php is done in an extended form. Through these extensions, we can easily complete a series of actions in the process.
  • pcntl extension: the main process extension, the completion process is created in the waiting operation.
  • posix extension: complete common API of POSIX compatible machine, such as obtaining process id, killing process, etc.
  • sysvmsg extension: the message queue for inter-process communication in system v mode.
  • sysvsem extension: realize the semaphore of system v mode.
  • sysvshm extension: to achieve shared memory in system v mode.
  • Sockets extension: realize socket communication.
These extensions can only be used in Linux/mac and are not supported under windows. Finally, it is recommended that the PHP version is 5.5+.

3. Example

A simple PHP multi-process example, in this example, a child process, a parent process. The child process outputs 5 times and exits the program.
$parentPid = posix\_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
$pid = pcntl\_fork();
if ( $pid == -1) {
    // creation failed
    exit("fork progress error!\n");
} else if ($pid == 0) {
    // The child process executes the program
    $pid = posix\_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        echo "({$pid})child progress is running! {$i} \n";
        $rand = rand(1,3);
        sleep($rand);
    }
    exit("({$pid})child progress end!\n");
} else {
    // The parent process executes the program
    $childList[$pid] = 1;
}
// Wait for the end of the child process
pcntl\_wait($status);
echo "({$parentPid})main progress end!";

Perfect, finally created a child process, a parent process. Is it over? No, the various processes are independent of each other, there is no intersection, and the scope of use is severely affected by the present. It is based on interprogress communication.

4. Inter-process communication (IPC)

Usually, the process communication methods in Linux are message queue, semaphore, shared memory, signal, pipe, socket.

1. Message queue

The message queue is a queue stored in memory. The following code will create 3 producer child processes and 2 consumer child processes. These 5 processes will communicate through the message queue.
$parentPid = posix\_getpid();
echo "parent progress pid:{$parentPid}\n";$childList = array();
// Create a message queue and define the message type (similar to the library in the database)
$id = ftok(\_\_FILE\_\_,'m');
$msgQueue = msg\_get\_queue($id);
const MSG\_TYPE = 1;
// Producer
function producer(){
    global $msgQueue;
    $pid = posix\_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        $str = "({$pid})progress create! {$i}";
        msg\_send($msgQueue,MSG\_TYPE,$str);
        $rand = rand(1,3);
        sleep($rand);
    }
}
// Consumer
function consumer(){
    global $msgQueue;
    $pid = posix\_getpid();
    $repeatNum = 6;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        $rel = msg\_receive($msgQueue,MSG\_TYPE,$msgType,1024,$message);
        echo "{$message} | consumer({$pid}) destroy \n";
        $rand = rand(1,3);
        sleep($rand);
    }
}
function createProgress($callback){
    $pid = pcntl\_fork();
    if ( $pid == -1) {
        // creation failed
        exit("fork progress error!\n");
    } else if ($pid == 0) {
        // The child process executes the program
        $pid = posix\_getpid();
        $callback();
        exit("({$pid})child progress end!\n");
    }else{
        // The parent process executes the program
        return $pid;
    }
}
// 3 writing processes
for ($i = 0; $i < 3; $i ++ ) {
    $pid = createProgress('producer');
    $childList[$pid] = 1;
    echo "create producer child progress: {$pid} \n";
}
// 2 writing processes
for ($i = 0; $i < 2; $i ++ ) {
    $pid = createProgress('consumer');
    $childList[$pid] = 1;
    echo "create consumer child progress: {$pid} \n";
}
// Wait for all child processes to end
while(!empty($childList)){
    $childPid = pcntl\_wait($status);
    if ($childPid > 0){
        unset($childList[$childPid]);
    }
}
echo "({$parentPid})main progress end!\n";

Since the message queue goes to the data, only one process can go, so no additional locks or semaphores are needed.

2. Semaphore and shared memory

Signal: It is an atomic operation provided by the system, a semaphore, and only your process can operate at the same time. When a process acquires a certain semaphore, it must be released by the process. Shared memory: It is a common memory area opened up in the memory by the system, which can be accessed by any process. At the same time, multiple processes can access this area. In order to ensure data consistency, the memory area needs to be locked or signaled. quantity. Below, create multiple processes to modify the same value in memory.
$parentPid = posix\_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();

// Create shared memory, create semaphore, define shared key
$shm\_id = ftok(\_\_FILE\_\_,'m');
$sem\_id = ftok(\_\_FILE\_\_,'s');
$shareMemory = shm\_attach($shm\_id);
$signal = sem\_get($sem\_id);
const SHARE\_KEY = 1;
// Producer
function producer(){
    global $shareMemory;
    global $signal;
    $pid = posix\_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        // get semaphore
        sem\_acquire($signal);

        if (shm\_has\_var($shareMemory,SHARE\_KEY)){
            // has value, plus one
            $count = shm\_get\_var($shareMemory,SHARE\_KEY);
            $count ++;
            shm\_put\_var($shareMemory,SHARE\_KEY,$count);
            echo "({$pid}) count: {$count}\n";
        }else{
            // No value, initialization
            shm\_put\_var($shareMemory,SHARE\_KEY,0);
            echo "({$pid}) count: 0\n";
        }
        // Release when used up
        sem\_release($signal);

        $rand = rand(1,3);
        sleep($rand);
    }
}
function createProgress($callback){
    $pid = pcntl\_fork();
    if ( $pid == -1) {
        // creation failed
        exit("fork progress error!\n");
    } else if ($pid == 0) {
        // The child process executes the program
        $pid = posix\_getpid();
        $callback();
        exit("({$pid})child progress end!\n");
    }else{
        // The parent process executes the program
        return $pid;
    }
}
// 3 writing processes
for ($i = 0; $i < 3; $i ++ ) {
    $pid = createProgress('producer');
    $childList[$pid] = 1;
    echo "create producer child progress: {$pid} \n";
}
// Wait for all child processes to end
while(!empty($childList)){
    $childPid = pcntl\_wait($status);
    if ($childPid > 0){
        unset($childList[$childPid]);
    }
}
// Release shared memory and semaphore
shm\_remove($shareMemory);
sem\_remove($signal);
echo "({$parentPid})main progress end!\n";

3. Signal

A signal is a system call. Usually, the kill command we use is to send a signal to a process. What specific signals can be run in Linux/mackill -lCheck. In the following example, the parent process waits for 5 seconds and sends a SIGINT signal to the child process. The child process captures the signal and discards the signal processing function for processing.
$parentPid = posix\_getpid();
echo "parent progress pid:{$parentPid}\n";

// Define a signal processing function
function sighandler($signo) {
    $pid = posix\_getpid();
    echo "{$pid} progress,oh no ,I'm killed!\n";
    exit(1);
}

$pid = pcntl\_fork();
if ( $pid == -1) {
    // creation failed
    exit("fork progress error!\n");
} else if ($pid == 0) {
    // The child process executes the program
    // Register signal processing function
    declare(ticks=10);
    pcntl\_signal(SIGINT, "sighandler");
    $pid = posix\_getpid();
    while(true){
        echo "{$pid} child progress is running!\n";
        sleep(1);
    }
    exit("({$pid})child progress end!\n");
}else{
    // The parent process executes the program
    $childList[$pid] = 1;
    // After 5 seconds, the parent process sends a sigint signal to the child process.
    sleep(5);
    posix\_kill($pid,SIGINT);
    sleep(5);
}
echo "({$parentPid})main progress end!\n";

4. Pipes (famous pipes)

Pipes are a commonly used method of multi-process communication. Pipes are divided into unnamed pipes and named pipes. Unnamed pipes can only be used for communication between processes with kinship, while named pipes can be used for any process on the same host. Only well-known pipes are introduced here. In the following example, the child process writes data and the parent process reads data.
// Define the pipeline path, and create the pipeline
$pipe\_path = '/data/test.pipe';
if(!file\_exists($pipe\_path)){
    if(!posix\_mkfifo($pipe\_path,0664)){
        exit("create pipe error!");
    }
}
$pid = pcntl\_fork();
if($pid == 0){
    // Child process, write data to the pipe
    $file = fopen($pipe\_path,'w');
    while (true){
        fwrite($file,'hello world');
        $rand = rand(1,3);
        sleep($rand);
    }
    exit('child end!');
}else{
    // The parent process, read data from the pipe
    $file = fopen($pipe\_path,'r');
    while (true){
        $rel = fread($file,20);
        echo "{$rel}\n";
        $rand = rand(1,2);
        sleep($rand);
    }
}

5.socket

Socket is what we often call socket programming. We will discuss Socket in the next post.