[Linux operating system] Detailed explanation of pipeline process communication in Linux system programming

In Linux system programming, pipes are a commonly used inter-process communication method. It can realize data transmission between parent and child processes or between sibling processes. This article will introduce how to use pipelines for process communication in Linux systems, and give corresponding code examples.

insert image description here

1. The concept of pipeline

A pipe is a special file that provides a buffer for data transfer between processes. Pipes can be divided into two types: anonymous pipes and named pipes.

  • Anonymous pipe : An anonymous pipe is a temporary pipe that can only be used between related processes and is usually used for communication between parent and child processes. An anonymous pipe can only be used between the process that created it and its child processes, and cannot be accessed by other processes.
  • Named Pipes : A named pipe is a pipe with a name that can communicate between different processes. Named pipes are implemented by creating a file in the file system through which processes can read and write data.

In this article, we will focus on the use of anonymous pipes.

2. Creation and use of pipelines

2.1 Prototype

In Linux systems, pipefunctions can be used to create a pipeline. pipeThe prototype of the function is as follows:

int pipe(int pipefd[2]);

pipefdIs an integer array used to store the read and write file descriptors of the pipe. pipefd[0]For reading data in the pipe, pipefd[1]for writing data in the pipe.

2.2 Examples

Here is a simple sample code that demonstrates how to use pipes for communication between parent and child processes:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {
    
    
    int pipefd[2];
    pid_t pid;
    char buf[1024];

    // 创建管道
    if (pipe(pipefd) == -1) {
    
    
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    pid = fork();
    if (pid == -1) {
    
    
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
    
    
        // 子进程写入数据到管道
        close(pipefd[0]); // 关闭读取端
        char* msg = "Hello, parent!";
        write(pipefd[1], msg, strlen(msg) + 1);
        close(pipefd[1]); // 关闭写入端
        exit(EXIT_SUCCESS);
    } else {
    
    
        // 父进程读取管道中的数据
        close(pipefd[1]); // 关闭写入端
        read(pipefd[0], buf, sizeof(buf));
        printf("Received message from child: %s\n", buf);
        close(pipefd[0]); // 关闭读取端
        exit(EXIT_SUCCESS);
    }
}

In the above code, first pipea pipeline is created using a function. Then forka subprocess was created using the function. The child process uses writefunctions to write data to the pipe, and the parent process uses readfunctions to read data from the pipe.

3. Parent-child process communication

After the parent process creates a pipeline and creates a child process, the parent process sends data to the child process through the pipeline, and the child process receives the data sent by the parent process through the pipeline.

The following is a sample code that demonstrates the process of using pipes to communicate between parent and child processes:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {
    
    
    int pipefd[2];
    pid_t pid;
    char buf[1024];

    // 创建管道
    if (pipe(pipefd) == -1) {
    
    
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    pid = fork();
    if (pid == -1) {
    
    
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
    
    
        // 子进程读取管道中的数据
        close(pipefd[1]); // 关闭写入端
        read(pipefd[0], buf, sizeof(buf));
        printf("Received message from parent: %s\n", buf);
        close(pipefd[0]); // 关闭读取端
        exit(EXIT_SUCCESS);
    } else {
    
    
        // 父进程写入数据到管道
        close(pipefd[0]); // 关闭读取端
        char* msg = "Hello, child!";
        write(pipefd[1], msg, strlen(msg) + 1);
        close(pipefd[1]); // 关闭写入端
        exit(EXIT_SUCCESS);
    }
}

In the above code, first pipea pipeline is created using a function. Then forka subprocess was created using the function. The child process uses readfunctions to read data from the pipe, and the parent process uses writefunctions to write data to the pipe.

4. Communication between sibling processes

To achieve communication between sibling processes, you can use named pipes (named pipe) or shared memory (shared memory) to achieve.

  1. Using named pipes:

    • Sibling processes can communicate by creating a named pipe.
    • One sibling process writes data to the named pipe, and the other sibling process reads data from the named pipe.
    • Sibling processes need to use the same named pipe name to communicate.
    • You can use mkfifofunctions to create named pipes and use openfunctions to open pipes for reading and writing.
  2. Use shared memory (shared memory):

    • Sibling processes can communicate by creating a shared memory area.
    • One sibling process writes data to shared memory, and the other sibling process reads data from shared memory.
    • Sibling processes need to use the same shared memory identifier to communicate.
    • You can use shmgetfunctions to create shared memory, and use shmatfunctions to attach shared memory to the address space of a process for read and write operations.

The following is a sample code using named pipes to demonstrate the communication process between sibling processes:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

int main() {
    
    
    pid_t pid;
    char buf[1024];
    const char* fifoName = "/tmp/myfifo";

    // 创建命名管道
    mkfifo(fifoName, 0666);

    // 创建子进程
    pid = fork();
    if (pid == -1) {
    
    
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
    
    
        // 子进程从命名管道中读取数据
        int fd = open(fifoName, O_RDONLY);
        read(fd, buf, sizeof(buf));
        printf("Received message from sibling: %s\n", buf);
        close(fd);
        exit(EXIT_SUCCESS);
    } else {
    
    
        // 父进程向命名管道中写入数据
        int fd = open(fifoName, O_WRONLY);
        char* msg = "Hello, sibling!";
        write(fd, msg, strlen(msg) + 1);
        close(fd);
        exit(EXIT_SUCCESS);
    }
}

In the above code, first mkfifoa named pipe is created using the function. Then forka subprocess was created using the function. The child process uses openfunctions to open and read from named pipes, and the parent process uses openfunctions to open and write to named pipes.

5. fifo function

The following is a sample code using the mkfifoand openfunction to demonstrate the communication process between sibling processes:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

int main() {
    
    
    pid_t pid;
    char buf[1024];
    const char* fifoName = "/tmp/myfifo";

    // 创建命名管道
    mkfifo(fifoName, 0666);

    // 创建子进程
    pid = fork();
    if (pid == -1) {
    
    
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
    
    
        // 子进程从命名管道中读取数据
        int fd = open(fifoName, O_RDONLY);
        read(fd, buf, sizeof(buf));
        printf("Received message from sibling: %s\n", buf);
        close(fd);
        exit(EXIT_SUCCESS);
    } else {
    
    
        // 父进程向命名管道中写入数据
        int fd = open(fifoName, O_WRONLY);
        char* msg = "Hello, sibling!";
        write(fd, msg, strlen(msg) + 1);
        close(fd);
        exit(EXIT_SUCCESS);
    }
}

In the above code, first mkfifoa named pipe is created using the function. Then forka subprocess was created using the function. The child process uses openfunctions to open and read from named pipes, and the parent process uses openfunctions to open and write to named pipes.

6. fifo implements blood relationship inter-process communication

The following is a sample code for non-blood relationship interprocess communication using named pipes:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

int main() {
    
    
    pid_t pid;
    char buf[1024];
    const char* fifoName = "/tmp/myfifo";

    // 创建命名管道
    mkfifo(fifoName, 0666);

    // 创建子进程
    pid = fork();
    if (pid == -1) {
    
    
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
    
    
        // 子进程向命名管道中写入数据
        int fd = open(fifoName, O_WRONLY);
        char* msg = "Hello, sibling!";
        write(fd, msg, strlen(msg) + 1);
        close(fd);
        exit(EXIT_SUCCESS);
    } else {
    
    
        // 父进程从命名管道中读取数据
        int fd = open(fifoName, O_RDONLY);
        read(fd, buf, sizeof(buf));
        printf("Received message from sibling: %s\n", buf);
        close(fd);
        exit(EXIT_SUCCESS);
    }
}

In the above code, first mkfifoa named pipe is created using the function. Then forka subprocess was created using the function. The child process uses openthe function to open and write data to the named pipe, and the parent process uses openthe function to open the named pipe and read data from it.

7. Properties and limitations of pipelines

As a means of interprocess communication, pipes have the following characteristics and limitations:

  • Pipes are half-duplex, i.e. data can only flow in one direction.
  • The pipeline has a limited length. Once it is full of data, further writing will be blocked until a process reads the data before continuing to write.
  • Pipes can only be used between processes that have a relationship, that is, between parent and child processes or sibling processes.

8. Summary

  1. fifofunction: There is no function named in the C standard library fifo.

  2. Named pipe (FIFO): A named pipe is a special file that can be created in the file system and can be opened and read and written by different processes. Use mkfifofunctions to create named pipes.

  3. Communication between sibling processes: A sibling process refers to multiple child processes created by the same parent process. Sibling interprocess communication can be implemented using named pipes, where one process writes data to the named pipe and the other process reads data from the named pipe.

  4. Non-blood relationship inter-process communication: A non-blood relationship process refers to a process that does not have a common parent process. Non-blood relationship interprocess communication can also be implemented using named pipes, where one process writes data to the named pipe, and the other process reads data from the named pipe.

Guess you like

Origin blog.csdn.net/Goforyouqp/article/details/132295877