Linux learning summary (10) IPC method-pipe PIPE

IPC method

In the Linux environment, the process address space is independent of each other. Each process has a different user address space. The global variables of any process cannot be seen in another process. Therefore, the process and the process cannot access each other, and exchange data. A buffer must be opened in the kernel through the kernel. Process 1 copies the data from the user space to the kernel buffer, and process 2 reads the data from the kernel buffer. This mechanism provided by the kernel becomes the inter-process communication (IPC) .

Insert picture description here
The completion of data transfer between processes requires special methods provided by the operating system, such as files, pipes, signals, shared memory, sockets, and named pipes. With the rapid development of computers, some methods have been eliminated or abandoned due to their own design flaws. The commonly used inter-process communication methods today are:

  • Pipe (the easiest to use)
  • Signal (minimum overhead)
  • Shared mapping area (no blood relationship)
  • Local socket (most stable)

pipeline

The pipe is one of the most basic IPC mechanisms, acting between blood-related processes to complete data transfer. A pipe can be created by calling the pipe system function. The pipeline characteristics are as follows:

  • The pipe is essentially a pseudo file (actually a kernel buffer)
  • Referenced by two file descriptors, one for the read end and one for the write end
  • Specifies that data flows from the write end of the pipe into the pipe and flows out from the read end

The principle of the pipeline: the pipeline actually uses the ring queue mechanism for the kernel, which is realized with the help of the kernel buffer (4k).
Limitations of the pipeline:

  • Data can not be written by itself
  • Once the data is read, it does not exist in the pipeline and cannot be read repeatedly
  • Since the pipeline uses half-duplex communication, data can only flow in one direction
  • Only use pipes between processes that have a common ancestor

Common communication methods are: simplex communication (broadcast), half-duplex communication (send voice through WeChat), and full-duplex communication (phone)

pipe function

Create pipeline

int pipe(int pipefd[2]);
return 0 if successful; return -1 if failed, set errno

The pipe function successfully returns two file descriptors r/w, no need to open, but manual close is required. Provisions:

fd[0]→r read end
fd[1]→w write end

Just like 0 corresponds to standard input and 1 corresponds to standard output, reading and writing data to the pipeline file is reading and writing the kernel buffer in real time .
After the pipeline is successfully created, the process that created the pipeline (the parent process) simultaneously controls the reading and writing ends of the pipeline. How to realize the communication between the parent and child processes? The following steps can usually be taken:
Insert picture description here
1. The parent process calls the pipe function to create a pipe, and gets two file descriptors fd[0] and fu[1] pointing to the read end and write end of the pipe.
2. The parent process calls fork to create the child process, then the child process also has two file descriptors pointing to the same pipe.
3. The parent process closes the pipe reading end, the child process closes the pipe writing end, the parent process can write data to the pipe, and the child process reads the data in the pipe. Because the pipeline is realized by using a circular queue, data flows into the pipeline from the writing end and flows out from the reading end, thus realizing inter-process communication.

Pipeline read and write behavior

You need to pay attention to the following 4 special cases when using pipes (assuming that they are all blocking I/O operations and the O_NONBLOCK flag is not set)

  • If all file descriptors pointing to the writing end of the pipe are closed (the reference count of the writing end of the pipe is 0), and there are still processes reading data from the reading end of the pipe, then after the remaining data in the pipe has been read, the read will return again 0, as at the end of the supervision document.
  • If a file descriptor pointing to the write end of the pipe is not closed (the reference count of the write end of the pipe is greater than 0), and the process holding the write end of the pipe does not write data to the pipe, then there is a process reading data from the read end of the pipe, then the pipe type After the remaining data is read, the read will block again, and the data will not be read and returned until the pipeline is readable.
  • If all file descriptors pointing to the read end of the pipe are closed (the reference count of the read end of the pipe is 0), then a process writes to the write end of the pipe, then the process will be SIGPIPE, which will usually cause the process to terminate abnormally. Of course, you can also capture the SIGPIPE signal without terminating the process.
  • If the file descriptor pointing to the read end of the pipe is not closed (the reference technology of the read end of the pipe is greater than 0), and the process holding the read end of the pipe does not read data from the pipe, then a process writes data to the write end of the pipe, then in the pipe When it is full, write will block again, and will not write data and return until there is an empty position in the pipeline.

Summary:
①Read the pipeline:
1. There is data in the pipeline, read returns the number of bytes actually read.
2. There is no data in the pipeline:
    (1) The write end of the pipeline is closed, read returns 0 (as if reading to the end of the file)
    (2) The write end is not all closed, read is blocked and waits (data may arrive in the near future, The cpu will be released at this time)
②Write to the pipeline:
1. The read ends of the pipeline are all closed, and the process terminates abnormally (the SIGPIPE signal can also be used to make the process not terminate)
2. The read ends of the pipeline are not all closed:
   (1) The pipeline is already closed Full, write blocked.
   (2) The pipeline is not full, write writes the data and returns the number of bytes actually written.

Exercise: Use pipes to achieve communication between parent and child processes, complete: ls | wc -l. Assume that the parent process implements ls and the child process implements wc.
The ls command normally writes the result set to stdout, but now it writes to the write end of the pipe; wc -l normally reads data from stdin, but it reads from the read end of the pipe.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    
    
	pid_t pid;
	int fd[2];

	pipe(fd);
	pid = fork();

	if (pid == 0) {
    
      //child
		close(fd[1]);	                //子进程从管道中读数据,关闭写端
		dup2(fd[0], STDIN_FILENO);		//让wc从管道中读取数据
		execlp("wc", "wc", "-l", NULL);	//wc命令默认从标准读入取数据

	} else {
    
    

		close(fd[0]);	//父进程向管道中写数据,关闭读端
		dup2(fd[1], STDOUT_FILENO);		//将ls的结果写入管道中
		execlp("ls", "ls", NULL);		//ls输出结果默认对应屏幕
	}

	return 0;
}

When the program is executed, it is found that the execution of the program ends, and the shell is still blocking waiting for user input. This is because, shell→fork→./pipe1, the child process of the program pipe1 redirects stdin to the pipe, and the ls executed by the parent process will pass the result set through The pipeline is written to the child process. If the parent process is called by the shell to call wait before the child process prints the result of wc to the screen, the shell will output the $ prompt first.

Exercise: Use pipes to communicate between brother processes. Brother: ls Brother: wc -l Father: Waiting to recycle the child process.
Requirement: Use cycle to create N child process model to create brother processes, use cycle silver i logo

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    
    
	pid_t pid;
	int fd[2], i;
	
	pipe(fd);

	for (i = 0; i < 2; i++) {
    
    
		if((pid = fork()) == 0) {
    
    
			break;
        }
    }

	if (i == 0) {
    
    			//兄
		close(fd[0]);				//写,关闭读端
		dup2(fd[1], STDOUT_FILENO);		
		execlp("ls", "ls", NULL);	
	} else if (i == 1) {
    
    	//弟
		close(fd[1]);				//读,关闭写端
		dup2(fd[0], STDIN_FILENO);		
		execlp("wc", "wc", "-l", NULL);		
	} else {
    
    
        close(fd[0]);
        close(fd[1]);
		for(i = 0; i < 2; i++)		//两个儿子wait两次
			wait(NULL);
	}

	return 0;
}

Test: Is it allowed, a pipe has one write end and multiple read ends? Is it allowed to have one read end and multiple write ends?

  • One reading and multiple writing will hang
  • One write and multiple reads will hang

hang, stop meaning

Pipe buffer size

Use the ulimit -a command to view the kernel buffer size corresponding to the pipe file created in the current system. Usually:
Insert picture description here

The pros and cons of the pipeline

advantage:

  • Simple. Compared with signals, sockets realize inter-process communication, which is much simpler.

Disadvantages:

  • Only one-way communication is possible, two-way communication needs to establish two channels
  • It can only be used for communication between father and son and sibling processes (with common ancestors). The problem was later solved using fifo's famous pipe

Guess you like

Origin blog.csdn.net/bureau123/article/details/112213307