Learn Linux series "19. Unnamed Pipe" from 0

Linux Interprocess Communication

When there are multiple processes in the system, communication between processes is particularly necessary. Processes are equivalent to people in the real world, and the communication between people is equivalent to the communication between processes. There are 7 main types of Inter Process Communication (IPC) in Linux: 1. Unnamed pipes 2.
Named Pipe
pipes Fifo
3. Signals Signal
4. Message queues Message Queue
5. Shared memory Share Memory
6. Semaphores Semphone
7. SocketsSocket

These seven methods have their own applicable occasions. In the early days, pipelines and signals were the main methods used for stand-alone IPC, AT&Tand Bell Labs expanded on it System V IPC, including shared memory, message queues, and semaphores. Three methods, and then BSD (California) Berkeley Software Research and Development Center) developed sockets for network communication. From this, it can also be concluded that network communication is actually the communication between processes between different machines. It is essentially inter-process communication, but there are more It's just a bridge to a network. This is the development process of the entire IPC. IPC is a very important module in Linux. It is necessary to master these 7 methods, which are also things that must be asked in the interview.

This article mainly introduces the mechanism of the first IPC: the unnamed pipe Pipe , and will analyze its implementation mechanism in the Linux kernel. Not much nonsense, hurry up and get on the bus...

What is an anonymous pipe?

shell pipe

Pipes are the oldest form of IPC in UNIX systems. All UNIX systems provide a pipe mechanism. If you have shellused pipes in , it should not be the default, for example:

ps -aux | grep "xxx"

This means that ps -auxthe output of is used as grep xxxthe input of , and two processes can be connected through a pipe. The function is very powerful, but there are some differences between the famous pipe and shellthe pipe of .

nameless pipe

A well-known pipe has the following three characteristics:
1. It can only be used for inter-process communication with kinship (parent-child process)
2. Half-duplex communication mode, with fixed read and write ends
3. Pipe is treated as a special file ( Everything is a file under Linux)

It is necessary to understand the difference between half-duplex and full-duplex:
1. Half-duplex: data can only be transmitted in one direction
at the same time 1. Full-duplex: data can be transmitted in two directions at the same time

The named pipe is half-duplex, and a process can only read or write at each moment, that is, only the read port or the write port can be opened, and cannot be opened at the same time. The following diagram can better explain the model of using pipes between parent and child processes:
pipe

In this model, the kernel has a pipe buffer, the parent process writes data to the pipe write end (fd[1]) , and the child process reads data from the pipe read end (fd[0]) .

Example: test_pipe.c

Knowing the basics of named pipes, let's use pipeto create a pipe, this is the pipe function definition:

#include <unistd.h>

/*
 * fd[0]:用于读取
 * fd[1]:用于写入
 * return:成功返回 0, 失败返回 -1,并设置 erron
 */
int pipe(int pipefd[2]);

In this example, we fork a child process in the parent process. What to do after fork depends on the direction of the data flow we want. Here we set the child process to read data from the parent process , so we need to close the write end of the child process. fd[1]And the read end of the parent processfd[0] , note that the unnamed pipe cannot be read and written at the same time .

// test_pipe.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>


int main() {
    int pfd[2];
    int pid;
    int status = 0;

    char w_cont[] = "Hello child, I'm parent!";
    char r_cont[255] = { 0 }; 
    int write_len = strlen(w_cont);

    // 创建管道
    if(pipe(pfd) < 0) {
        perror("create pipe failed"); 
        exit(1); 
    } else {
        // 创建子进程
        if((pid = fork()) < 0) {
            perror("create process failed");
    } else if(pid > 0) {
        // 关闭父进程读端
        close(pfd[0]); 
        // 父进程像写端写入数据
        write(pfd[1], w_cont, write_len); 
        close(pfd[1]);
        // 等待子进程结束
        wait(&status);
    } else { 
        sleep(2); 
        // 关闭子进程写端
        close(pfd[1]);
        // 子进程从读端读取数据
        read(pfd[0], r_cont, write_len);
        // 子进程输出读取的数据
        printf("child process read: %s\n", r_cont); 
    }

    return 0 ; 
}

Compile and run to see:

gcc test_pipe.c -o test_pipe
./test_pipe
child process read: Hello child, I'm parent!

It can be seen that the child process successfully read the data written by the parent process. The whole process is divided into 6 steps:
1. Create a pipeline
2. Create a child process
3. The parent process closes the read end and writes data to the write end
4. The child process waits for 2s and waits for the parent process to finish writing
5. The child process closes the write end, reads data from the read end and outputs
6. The parent process waits for the end of the child process with wait

This example can well explain the use of pipes: the parent process writes, the child process reads, of course, you can also set the child process to write, the parent process to read, just change the read and write ports and code logic of the process, code reference : test_pipe.c , test_pipe2.c

Kernel implementation of Pipe

The operation of the pipeline is relatively simple. In order to better understand its principle, let's take a look at how the pipeline in the Linux kernel is implemented. Because the modifications in different versions of the Linux kernel are relatively large, the Linux-3.4 version is used for analysis.

Pipe registration process

The implementation principle of the kernel's Pipe is generally as follows: Pipe maps an area in memory to the virtual file system VFS, so that upper-layer applications can operate Pipe like operating files, thereby realizing IPC, which means that Pipe is based on the pipeline file system. Yes , let's take a look fs/pipe.cat the registration process of the pipe file system in , which is actually a driver:

kernel pipe

This process registers the pipe's filesystem with the kernel, which is also controlled by the VFS.

The calling process of Pipe

Let's take a look at the calling process of the pipeline. The upper-level pipecalls generally correspond to the bottom-level sys_pipecalls, but with the modification of the kernel, some names will change. For example, sys_pipein 3.4, they are represented by macro definitions:

/*
 * fs/pipe.c
 * sys_pipe() is the normal C calling standard for creating
 * a pipe. It's not the way Unix traditionally does this, though.  
 **/
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{
    int fd[2];
    int error;

    error = do_pipe_flags(fd, flags);
    if (!error) {
        if (copy_to_user(fildes, fd, sizeof(fd))) {
            sys_close(fd[0]);
            sys_close(fd[1]);
            error = -EFAULT;
        }
    }

    return error;
}

This is the specific execution process:

sys_pipe

What this process does is mainly to apply for memory to the kernel, create read and write descriptors, and create a pipe file. The more important thing is create_write_pipethat this function creates a write pipeline and calls at the end kzallocto apply for memory space from the kernel:

crepipe

This also confirms that pipe maps an area in memory into a virtual file system and that Linux's inter-process communication is essentially the two concepts of IO operations.

Epilogue

This time, we learned about 7 ways of inter-process communication (IPC) under Linux , and focused on the first way: anonymous pipe . Pipe is the oldest IPC method, and it is relatively simple to use, and we also briefly analyzed the implementation process of pipe in the kernel. We know that pipe actually implements IPC in the form of file IO. We have a better understanding of IPC.

Thanks for reading, see you next time :)

This article was originally published on the WeChat public account "cdeveloper", programming, workplace, life, follow and reply to keywords "linux", "machine learning", etc. to obtain free learning materials.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324646632&siteId=291194637