进程间通信--管道

一、为什么要有进程间通信(目的)

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

二、怎样做到进程间通信?

无论是发送数据,还是共享数据或协同、控制

进程间通信的本质:是让不同的进程看到同一份资源

为了不破坏进程的独立性,这份资源不属于任何一个进程,而是由OS提供的一块特定形式的内存空间。

进程(用户)利用该空间进行通信,本质上就是访问OS。该空间的建立、释放,底层设计和接口都由OS来完成。

而管道是一种基于文件级别(不与磁盘交互)的通信方式。

三、匿名管道

1、匿名管道的原理/如何建立通信

进程间通信--管道_第1张图片

如图所示,父子进程(有血缘关系的进程)通过继承体系,继承Task_struct的文件描述符表

父进程以WR方式打开该文件,引用计数为2,fork创建子进程,引用计数变为4.

思考:通信时产生的  访问冲突,临界资源竞争

OS在设计上为了简化整个过程,采用了单向通信的模式,即一个读,另一个写。

为实现双向通信,可以再创建一个管道,让通信方向相反即可。

2、打开管道的系统调用接口pipe

进程间通信--管道_第2张图片

输出型参数  pipefd[0]  pipefd[1]分别为读写的fd。

例子:子进程sleep(1),父一直read

#define N 2
#define NUM 128
void Writer(int wfd)
{
    string str = "I am a child ";
    pid_t self = getpid();
    int number=0;

    //充当缓冲区
    char buffer[NUM];
    while(true)
    {
        //字符串清空,只是为了提醒阅读代码的人,把这个数组当成字符串了
        buffer[0]=0;

        snprintf(buffer,sizeof(buffer),"msg:%s--pid:%d--num:%d",str.c_str(),self,number++);
        write(wfd,buffer,strlen(buffer));//不用+1,系统层面不用加\0
        sleep(1);

    }
}
void Reader(int rfd)
{
    char buffer[NUM];
    while(true)
    {
        buffer[0]=0;
        ssize_t n = read(rfd,buffer,sizeof(buffer));
        if(n>0)
        {
            //读取之后按字符串处理
            buffer[n]='\0';
            printf("father get msg:%s father_pid:%d\n",buffer,getpid());
            // cout << "father get a message[" << getpid() << "]# " << buffer << endl;
        }
        else if(n==0)
        {
            cout<<"father read file done";
        }
        else break;
    }
}
// child--w   father--r
//IPC code
int main()
{
    int pipefd[N] = {0};
    int n = pipe(pipefd);
    if (n < 0)
        return 1;

    // cout<<"pipefd[0]:"<

进程间通信--管道_第3张图片

3、管道的特点

进程间通信--管道_第4张图片

进程退出,文件都关闭了,管道作为内存级文件也会被OS自动释放

4、管道4种情况

1、如果read完了管道内的所有数据,如果写端没有继续写入数据,那么读取端就只能继续等待。

w:1s写一次   r:读完后,也要等1s

2、如果写端把管道写满了就不能继续写入了。

w:短时间写多次直至写满,等待读取   r:5s读一次,一次读整个缓冲区大小

tips:管道大小

64kb 65536b

进程间通信--管道_第5张图片

读写atomic原子性问题。一次读写的数据作为一个整体的单位 PIPE_BUF为4kb

例如hello world是一体的,不会只读一部分hello

3、如果我关闭了写入端,读取完了管道内的数据,继续读就会返回0,表示读取到了文件的结尾。

进程间通信--管道_第6张图片

子进程退出后,父进程一直read(不阻塞),返回0表示读到文件结尾(多次调用read,每次都返回0,表明读到了文件结尾)

4、写端一直写入,但是把读端关闭,操作系统会直接杀死一直在写入的进程,并且关闭管道,操作系统会通过信号来终止进程13)SIGPIPE

读5s后关闭读端,立即发送13信号杀进程

进程间通信--管道_第7张图片

进程间通信--管道_第8张图片进程间通信--管道_第9张图片

四、管道应用--进程池

你可能感兴趣的:(Linux,is,not,unix,--,系统,服务器,运维,linux)