foreword
When we are learning process management and process replacement, we have emphasized it
进程的独立性
. What is inter-process communication? This seems to be independent of the process,相矛盾
right?
So today, we will learn进程间通信
, and the first communication method –管道
Article directory
1. Inter-process communication
Inter-process communication does not destroy the independence of the process, which we are
管道
explaining .
The purpose of process communication is as follows:
数据传输
: A process needs to convert its数据发送给另一个进程
资源共享
: between multiple processes共享同样的资源
通知事件
: A process needs to send a message to another process or a group of processes,通知
it (they) happened某种事件
(such as to notify the parent process when the process terminates)进程控制
: Some processes want to complete控制另一个进程的执行
(such as Debug process), at this time the control process wants to be able to拦截另一个进程的所有陷入和异常
find its state changes in time.
interprocess communication
三种常用方法
管道
anonymous pipe
named pipe
System V进程间通信
System V message queues
System V shared memory
System V semaphores
POSIX进程间通信
message queue
shared memory
information number
mutex
condition variable
read-write lock
进程依旧具有独立性
, It is impossible for a process to directly obtain data from the heap and stack area of another process, so how is inter-process communication realized?
To allow two different processes to communicate, the prerequisite is: first let the different processes,看到同一份“资源”
The pipeline is one of the ways to see the same "resource"
2. Pipeline
Pipeline is the oldest form of inter-process communication in Unix.
We call a data stream connecting one process to another process a "pipeline". What
we use in Linux commands|
is a pipeline
who | wc -l
. You canwho
check how many users are logged in to the server.wc
There are several lines of text for statistics.
Here is the who creation process. It first displays how many users there are, and then transmits the data to wc. After wc finishes processing, it outputs the result
Let's understand the pipeline more concretely
When we create a process, OS will create
task_struct
maintenance, management process. And there is one in the structurestrust file_struct*
, which points to a structure, which manages files and stores open files in it文件描述符
,默认0,1,2分别是标准输出,标准输入,标准错误
and everything under Linux is a file,管道也是文件
but it is for the OS to realize inter-process communication临时创建的一个内存文件
. The default is空闲文件描述符的后两个
. As shown below
To create a child process, you need to recreate task_struct, but the content of struct files_struct is copied from the parent process, but it is only a copy.
拷贝一份文件描述符和文件的映射关系,不会重新创建新文件
fork创建子进程后,只会赋值进程相关的数据结构对象,不会复制父进程曾经打开的文件对象!就像浅拷贝一样
This pipeline, 只支持单向通信
, is called 匿名管道
. Because of the file 只有一个缓冲区
, only one item can be read and written at the same time,
so we need to manually determine the data flow direction and close the unnecessary file descriptor fd
3. Use of anonymous channels
Next, let's briefly simulate inter-process communication.
To achieve process communication with anonymous pipes, 父进程创建匿名管道
the method of creation is to usepipe函数
The parameters of this function are special: Yes 输出型参数
. Similar to the status of waitpid.
We pass an integer array of size 2,pipe函数内部会将创建的管道的读和写两个文件描述符写入这个数组,返回给我们
Return value: successful call, return 0; error, return -1, and set 错误码
.
1. The use of pipe
Let's first use the pipe function to see its effect
#include<iostream>
#include<cerrno>
#include<unistd.h>
#include<string.h>
using std::cout;
using std::endl;
int main()
{
//创建管道所需传参的数组
int pipefd[2]={
0};
//1.创建管道
int n=pipe(pipefd);
if(n<0)
{
//如果返回值小于0,即-1,还会设置错误码
//我们再把错误码对应的错误信息,打印一下
cout<<"pipe error,"<<errno<<":"<<strerror(errno)<<endl;
return 1;
}
cout<<"pipefd[0]:"<<pipefd[0]<<endl;
cout<<"pipefd[1]:"<<pipefd[1]<<endl;
return 0;
}
As mentioned earlier, the pipe's two file descriptors, 默认使用当前空闲的前两个文件描述符
.
Two file descriptors created by the pipeline, default第一个是读,第二个是写
mnemonic
pipe[0]的是读端,0 -> 嘴巴 -> 读
pipe[1]的是写端,1 -> 笔 -> 写
2. Prepare for correspondence
We know how to create a pipeline, and then we can prepare to implement communication between parent and child processes.
As we mentioned above, the prerequisite for inter-process communication is to allow different processes to see the same resource.
The pipeline can be this resource. We simulate the communication between parent and child processes, let the child process write data into the pipeline, and then the parent process receives the data
code show as below:
#include<iostream>
#include<cerrno>
#include<cassert>
#include<unistd.h>
#include<string.h>
#include<string>
#include<sys/types.h>
using std::cout;
using std::endl;
int main()
{
//创建管道所需传参的数组
int pipefd[2]={
0};
//1.创建管道
int n=pipe(pipefd);
if(n<0)
{
//如果返回值小于0,即-1,还会设置错误码
//我们再把错误码对应的错误信息,打印一下
cout<<"pipe error,"<<errno<<":"<<strerror(errno)<<endl;
return 1;
}
cout<<"pipefd[0]:"<<pipefd[0]<<endl;//读端
cout<<"pipefd[1]:"<<pipefd[1]<<endl;//写端
//2.创建子进程
pid_t id = fork();
//获取错误。意料之外,使用if;意料之中,用assert
//此处应该使用if,但为了简单一些,使用assert
assert(id!=-1);
if(id==0)
{
//子进程
//3.关闭不需要的fd
close(pipefd[0]);//关闭子进程的读端
//4.开始通信
const std::string namestr="hello ,我是子进程";
int cnt=1;//计数器
char buffer[1024];//write的字符数组
while(true)
{
//将内容写入buffer字符串
snprintf(buffer,sizeof(buffer)-1,"%s,计数器:%d,我的PID:%d\n",namestr.c_str(),cnt++,getpid());
//将内容写入管道
write(pipefd[1],buffer,strlen(buffer));
sleep(1);
}
//关闭子进程的写端,再exit退出
close(pipefd[1]);
exit(0);
}
//父进程
//3.关闭不需要的fd
//让父进程进行读取
close(pipefd[1]);//关闭父进程的写端
//4.开始通信
char buffer[1024];
while(true)
{
//读取的大小,至少要留一个位置写入\0
int n = read(pipefd[0],buffer,sizeof(buffer)-1);
if(n>0)
{
buffer[n]='\0';
cout<<"我是父进程, child give me a message: "<<buffer<<endl;
}
}
//关闭父进程的读端,结束进程
close(pipefd[0]);
return 0;
}
In this way, we have realized the communication between the parent and child processes.
3. Features and scenarios of anonymous pipes
- When we comment out the sleep(1) that the child process writes data to. The result of the program running becomes different.
We see that the child process writes many times, and the parent process only reads once.
Let's change it again. After the child process writes, the sleep is changed to sleep(5)
. When the parent process reads data, we read 10 bytes and 10 bytes.
The program running result changes again
These two experiments have verified such a conclusion:
In the communication of anonymous pipelines,写入的次数,和读取的次数,不是严格匹配的
there is no strong correlation between the number of reads and writes—because the buffer reads and writes are字节
in units—字节流
- Next, let's do another experiment:
we let the parent process read data normally, but the child process writes every time at an interval of 10 seconds.
Observing the operation, we found that we made the writing of the child process slower, but the reading of the parent process also slowed down. What's going on here?
First of all, the data of the pipeline file is similar to a queue. Writing once is entering the queue, and reading is exiting the queue.
只要读取,数据就没了。
Therefore,子进程写入变慢,父进程没有东西可读,就进入了阻塞状态。
- Let's make the reading of the parent process slower, and the child process writes normally
We found that
65536(从0开始)次
after the pipeline was written, it was not written. When the parent process time is up, we read a lot of X
and every time we write, we only write 1 byte. So the pipe can write at most65536字节
, that is2的16次方
,64kb
,16个数据块。
- What happens if we close the write end of the child process and continue the read end of the parent process?
We let the child process write data once and then close the write terminal. The parent process still reads data all the time, but it needs to make an extra judgment on the return value of read. The running
results are as follows
When we
关闭子进程的写端,父进程再读取就会读到文件尾,就会返回0
, the parent process terminates.
- What happens if we close the read end of the parent process?
Straight to the conclusion:
when a pipeline has only a writing end and no reading end, it means that no matter how it is written, no one will get没有意义
it操作系统不会维护无意义的,低效率的,或者浪费资源的事情
. The OS will kill this process that has been writing!通过13号信号 SIGPIPE,杀死进程
Next, we summarize the characteristics and scenarios of anonymous pipes
特点
单向通信
,半双工
in one case, only one of the two parties can write at the same time.
Because of the anonymous pipe只有一个缓冲区
, only one party can read and write at the same time.
全双工
, both parties can simultaneously write- The essence of anonymous pipes is that
文件
, becausefd的生命周期随进程
, so管道的生命周期也是随进程的。
- Anonymous pipe communication is usually used for communication
具有“血缘关系”的进程之间的进程通信
, because anonymous pipes are内存级文件
, so only the created child process can obtain the anonymous pipe created by the parent process, so it is often used父子间通信 -- pipe 打开匿名管道。
4. In the communication of anonymous pipes,写入的次数,和读取的次数,不是严格匹配的
the number of reads and writes is not strongly related — Because the buffer reads and writes字节
in units —字节流
- Have a certain
协同能力
, so that read and write can communicate according to certain steps—自带同步机制
场景
- If we read, the reading end has finished reading all the pipeline data, if the other party does not send it, the reading end will
堵塞
- If we write, write to the end,
管道写满了
then暂时
we can’t continue to write. If necessary读端读取数据
, the read data is removed from the pipeline, and we can continue to write- If we
关闭了写端
,读取完毕管道数据
, read again, it will be read文件尾
, and read will return0
.- The write end keeps writing,
读端关闭
and the operating system will send13号 SIGPIPE信号
the process to kill the write end.
When the amount of data written in a single time is not greater than PIPE_BUF, LInux will guarantee that the amount of data written 原子性
is greater than PIPE_BUF, and Linux will no longer guarantee the atomicity of writing.
目前的理解是,保证写入时不会被读取
conclusion
This concludes the content of this blog.
If you think this article is helpful to you, you might as well like it to support the blogger, please, this is really important to me.