Linux inter-process communication - pipeline (on)

Table of contents

Preamble

1. Introduction to inter-process communication

Second, what is a pipeline?

Three, the basic principle of the pipeline

3.1 Anonymous pipes

3.2 Fundamentals of piping

Four, sample code

5. Pipeline reading and writing rules

Six, the characteristics of the pipeline

Summarize


Preamble

This article mainly explains the main content of the pipeline in inter-process communication, such as the basic principle, sample code and characteristics, etc.

1. Introduction to inter-process communication

First of all, inter-process communication refers to the dissemination or exchange of information between different processes . As we all know, in Linux, each process is independent of each other, which makes it difficult to communicate independently between processes, so processes want to communicate Communication requires the help of a third party, which can also be regarded as a medium for inter-process communication. In the development of inter-process communication, the following three main media are used: pipelines, System V inter-process communication, and POSIX inter-process communication

The main purpose of inter-process communication is as follows

Data transfer: One process needs to send its data to another process
Resource sharing: The same resource is shared between multiple processes.
Notification event: A process needs to send a message to another process or a group of processes, informing it (they) that some event has occurred (such as notifying the parent process when the process terminates).
Process control: Some processes want to completely control the execution of another process (such as Debug process). At this time, the control process hopes to be able to intercept all traps and exceptions of another process, and to be able to know its state changes in time.

This article mainly explains the pipeline in inter-process communication.

Second, what is a pipeline?

  • Pipes are the oldest form of interprocess communication in Unix.

  • We call a flow of data from one process to another a "pipe"

     

    As above, the who | wc -l command is a simple application of the pipeline. The content executed by the who process is passed into the pipeline, and then the wc process reads the content in the pipeline and completes its own functions, so that the two processes do not destroy In the case of independence, the same resource (that is, the content displayed by the who command) is seen through the pipeline to complete inter-process communication.

Three, the basic principle of anonymous pipeline

First of all, pipelines are mainly divided into anonymous pipelines and named pipelines, and we use anonymous pipelines to explain the principles of pipelines and their sample codes.

3.1 Anonymous pipes

First of all, an anonymous pipe refers to an unnamed pipe created with the pipe function. The required header files and function prototypes are as follows

#include <unistd.h>
int pipe(int fd[2]);

parameter

fd: file descriptor array, where fd[0] represents the read end, fd[1] represents the write end
Return value: returns 0 on success, returns an error code on failure

Therefore, from the above file descriptor array and the principle that everything is a file under Linux, we can deduce that pipes are also files

3.2 Fundamentals of Anonymous Pipelines

The implementation of the pipeline mainly relies on fork to share the pipeline. The main process is as follows ( the following are all understanding pipelines from the perspective of file descriptors ):

 1. The parent process creates a pipeline

 As shown above, the parent process first creates a pipeline with the pipe function, fd[0] (corresponding to 3 in the file descriptor table) corresponds to the read pipeline, and fd[1] (corresponds to 4 in the file descriptor table) corresponds to the write pipeline

 2. The parent process forks out the child process

 As shown above, the child process from the fork of the parent process inherits the file descriptor table of the parent process (note that this is a shallow copy, so the child process does not create a new pipeline), so fd[0], fd[1] of the child process The content pointed to is consistent with the parent process.

3. The parent and child processes close unnecessary fds respectively (here we take the parent process writing and the child process reading as an example, and the usage scenarios are mainly used in use, and there is no need to stick to the parent writing and child reading)

 As shown in the figure above, when the parent process writes, it will close fd[0], and the child process will close fd[1] when it reads. Since then, the parent process can see the same resource through the pipeline, and then it can be used without destroying Process communication with process independence

Therefore, in fact, the above three steps can be regarded as a communication scheme to allow the parent and child processes to see the same resource and communicate

Four, sample code

The basic principle of the anonymous pipeline has been explained. Next, we complete the sample code according to the above principle, and conduct related experiments through the sample code to further explore the nature and characteristics of the pipeline. The sample code is as follows

#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <string>
#include <cassert>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
using namespace std;

int main()
{
    //1.创建管道
    int mypipe[2]={0};
    int n=pipe(mypipe);
    if(n<0)//创建失败报错返回
    {
        cout<<"pipe error: "<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }

    cout<<"mypipe[0]: "<<mypipe[0]<<endl;//[0]-0-张嘴读
    cout<<"mypipe[1]: "<<mypipe[1]<<endl;//[1]-1-用笔写

    //2.创建子进程
    pid_t fd=fork();
    assert(fd!=-1);//判断创建是否成功

    //子进程
    if(fd==0)
    {
        //3.父进程写入,子进程读取
        close(mypipe[1]);

        //4.通信
        char buffer[1024];
        while(true)
        {
            int n=read(mypipe[0],buffer,sizeof(buffer)-1);
            
            if(n>0)
            {
                buffer[n]='\0';
                cout<<"我是子进程,父进程给我的讯息是: "<<buffer<<endl;
            }
            
        }

        //退出
        close(mypipe[0]);
        exit(0);

    }

    //父进程
    //3.父进程写入,子进程读取
    close(mypipe[0]);
    
    //4.通信
    const string str=("hello,我是父进程");
    int cur=1;
    char buffer[1024];
    while(true)
    {
        sleep(1);//写入等待一秒

        snprintf(buffer,sizeof(buffer),"%s,计数器:%d,我的pid:%d",str.c_str(),cur++,getpid());
        write(mypipe[1],buffer,strlen(buffer));
        
    }


    close(mypipe[1]);
    return 0;
}

 The result of the operation is as follows

 

5. Pipeline reading and writing rules

1. When there is no data to read, if the other party does not send, we can only wait

 As shown in the figure above, when the write is set to write every five seconds, the reader will stop executing and wait for the data to be written after reading

 2. When the pipe is full, it cannot continue to write

 As shown in the figure above, we continue to write the letter a on the writing side, and use cur to record the number of written a, and then the reading side reads once every 10s. We found that before the first reading, cur is 65536 , that is to say, 65536 letters a should be written, but in fact we found that when the pipeline is full, it will not write

3. If the write end is closed, after the pipeline data is read, read read again will return 0, indicating that the read is over

 As shown in the figure above, after we stop writing, the pipeline reads again, the return value of read is 0, and the reading ends

4. The write end keeps writing, and the read end has been closed. At this time, the behavior of the write end is meaningless. OS will not allow meaningless behavior, low efficiency, and waste of resources. Therefore, it will kill the write end and send it through a signal. termination.

 As shown in the figure, when the reading end, that is, the child process stops reading, the writing end, that is, the parent process, is directly killed by the OS.

5. When the amount of data to be written is not greater than the capacity of the pipeline, Linux will guarantee the atomicity of writing: when the amount of data to be written is greater than the capacity of the pipeline, Linux will no longer guarantee the atomicity of writing

In other words, when the amount of data written is less than the capacity of the pipeline, Linux can guarantee the correctness of the data, otherwise the data may be distorted

Six, the characteristics of the pipeline

From the above content, the value pipeline we can have has the following characteristics

1. One-way communication, that is, its data flow can only flow in one direction

2. The essence of the pipeline is the file, and because the life cycle of fd (file operator) ends with the end of the process, the life cycle of the pipeline also ends with the end of the process

3. Processes with a blood relationship can use pipes for process communication, such as grandparent processes, father-son processes, and brother processes. This is because they all have a common ancestor. As long as the common ancestor calls pipe to create a pipe, their descendants can communicate with each other. pipe communication

4. There is no strong correlation between the read and write times of the two parties in the pipeline communication (byte stream), that is to say, they do not affect each other . For example, the above child process can read as often as it wants, and is not limited by the other party of the pipeline.

5. Have a certain coordination ability, so that both the reading end and the writing end can communicate according to certain rules - with its own synchronization mechanism (reading and writing rules)

Summarize

The above is all the content of this article. If you have received something, I hope to pay attention to it three times.

Guess you like

Origin blog.csdn.net/zcxmjw/article/details/131367115