Linux进程间通信

目录

进程间通信介绍

进程间通信目的

 进程间通信发展

 进程间通信分类

管道(基于文件)

 System V IPC(基于本地通信,不能跨网络)

POSIX IPC 

管道 

什么是管道

匿名管道

匿名管道的原理

任何进程通信的手段

用fork来共享管道原理 

 站在文件描述符角度-深度理解管道

站在内核角度-管道本质

​编辑

pipe函数 

pipe2

 进程通信的步骤

第一步,创建管道 

第二步,创建子进程

 第三步,关闭不需要的fd

 第四步,开始通信

管道的特点

 管道的四种场景

命名管道 


进程间通信介绍

进程间通信目的

数据传输:一个进程需要将它的数据发送给另一个进程

资源共享:多个进程之间共享同样的资源。

通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止 时要通知父进程)。

进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另 一个进程的所有陷入和异常,并能够及时知道它的状态改变。

 进程间通信发展

管道

System V进程间通信

POSIX进程间通信

 进程间通信分类

管道(基于文件)

匿名管道pipe

命名管道

 System V IPC(基于本地通信,不能跨网络)

System V 消息队列

System V 共享内存

System V 信号量

POSIX IPC 

消息队列

共享内存

信号量

互斥量

条件变量

读写锁

管道 

什么是管道

管道是Unix中最古老的进程间通信的形式。 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

匿名管道

匿名管道的原理

匿名管道用于进程间通信,且仅限于本地父子进程之间的通信

任何进程通信的手段

a.想办法,先让不同的进程,看到同一份资源

b.让一方写入,一方读取,完成通信过程,至于通信目的与后续工作,要结合具体场景

进程间通信的本质就是,让不同的进程看到同一份资源,使用匿名管道实现父子进程间通信的原理就是,让两个父子进程先看到同一份被打开的文件资源,然后父子进程就可以对该文件进行写入或是读取操作,进而实现父子进程间通信。 

——创建子进程的时候fork子进程,只会复制进程相关的数据结构对象 ,不会复制父进程曾经打开的文件对象

现象:这就是为什么fork之后,父子进程都printf,cout,都会向同一个显示器终端打印数据的原因

用fork来共享管道原理 

 站在文件描述符角度-深度理解管道

站在内核角度-管道本质

 

pipe函数 

 

#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

 

pipe2

pipe2函数与pipe函数类似,也是用于创建匿名管道,其函数原型如下:

int pipe2(int pipefd[2], int flags);

 

pipe2函数的第二个参数用于设置选项。

1、当没有数据可读时:

O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
2、当管道满的时候:

O_NONBLOCK disable:write调用阻塞,直到有进程读走数据。
O_NONBLOCK enable:write调用返回-1,errno值为EAGAIN。
3、如果所有管道写端对应的文件描述符被关闭,则read返回0。
4、如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出。
5、当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。
6、当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。

 进程通信的步骤

 用管道通信,大致分为四个步骤

 

第一步,创建管道 

 

查看一下管道文件是否创建成功

第二步,创建子进程

 第三步,关闭不需要的fd

 我们一般把pipefd[0]作为读端,pipefd[1]作为写端——0对应嘴巴用来读,1对应笔用来写

 

 第四步,开始通信

 

#include <iostream>
#include <string>
#include <cerrno>
#include <cassert>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// 让不同的进程看到同一份资源!!!!
    // 任何一种任何一种进程间通信中,一定要 先 保证不同的进程之间看到同一份资源
    int pipefd[2] = {0};
    //1. 创建管道
    int n = pipe(pipefd);
    if(n < 0)
    {
        std::cout << "pipe error, " << errno << ": " << strerror(errno) << std::endl;
        return 1;
    }
    std::cout << "pipefd[0]: " << pipefd[0] << std::endl; // 读端, 0->嘴巴->读书
    std::cout << "pipefd[1]: " << pipefd[1] << std::endl; // 写端, 1->笔->写东西的

    //2. 创建子进程
    pid_t id = fork();
    assert(id != -1); //正常应该用判断,我这里就断言:意料之外用if,意料之中用assert

    if(id == 0)// 子进程
    {
        //3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入
        close(pipefd[0]);

        //4. 开始通信 -- 结合某种场景
        const std::string namestr = "hello ,我是子进程";
        int cnt = 1;
        char buffer[1024];
        while(true)
        {
            snprintf(buffer, sizeof buffer, "%s, 计数器: %d, 我的PID: %d\n", namestr.c_str(), cnt++, getpid());
            write(pipefd[1], buffer, strlen(buffer));
            sleep(1);
        }

        close(pipefd[1]);
        exit(0);
    }

    //父进程
    //3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入
    close(pipefd[1]);

    //4. 开始通信 -- 结合某种场景
    char buffer[1024];
    while(true)
    {
        int n = read(pipefd[0], buffer, sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = '\0';
            std::cout << "我是父进程, child give me message: " << buffer << std::endl;
        }

    }
    close(pipefd[0]);

    return 0;

}

 

 这要一个简单的管道通信就写好了

这里有一个细节,在子进程写的时候每写一次sleep一秒

管道的特点

1.单向通信

2.管道的本质是文件,因为fd的生命周期随进程,管道的生命周期是随进程的

3.管道通信,通常用来进行具有“血缘”关系的进程,进行进程间通信。常用与父子通信——pipe打开管道,并不清楚管道的名字,匿名管道

4.在管道通信中,写入的次数,和读取的次数不是严格匹配的,读写次数的多少没有强相关--表现--字节流

5.具有一定的协同能力,让reader和writer能够按照一定的步骤进行通信--自带同步机制

 管道的四种场景

1.如果我们read读取完毕了所有的管道数据,如果对方不发,我们只能等待

2.如果我们write端将管道写满了,我们还能写吗?不能

3.如果我关闭了写端,读取完毕管道数据,再读,就会read返回0,表明读到了文件结尾

4.写端一直写,读端关闭,会发生什么呢?没有意义OS不会维护无意义,低效率,或者浪费资源的事情。OS会杀死一直在写入的进程!OS会通过信号来终止进程   13)SIGPIPE

————————————————————————12.15日,明天在写@_@ 

命名管道 

 

 

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-16 06:14:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-16 06:14:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-16 06:14:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-16 06:14:04       20 阅读

热门阅读

  1. LeetCode260. Single Number III

    2023-12-16 06:14:04       36 阅读
  2. windows命令

    2023-12-16 06:14:04       34 阅读
  3. 第21节: Vue3 计算缓存与方法

    2023-12-16 06:14:04       40 阅读
  4. git cherry-pick命令

    2023-12-16 06:14:04       32 阅读
  5. playwright元素定位

    2023-12-16 06:14:04       42 阅读
  6. 力扣二叉树--第四十一天

    2023-12-16 06:14:04       36 阅读
  7. php+html优化页面显示速度

    2023-12-16 06:14:04       32 阅读
  8. cfa一级考生复习经验分享系列(四)

    2023-12-16 06:14:04       39 阅读
  9. 物流Excel报表用python处理并进行数据分析

    2023-12-16 06:14:04       44 阅读
  10. Apache Avro编程快速入门

    2023-12-16 06:14:04       31 阅读
  11. List当中的stream流使用

    2023-12-16 06:14:04       41 阅读
  12. 二进制to十六进制

    2023-12-16 06:14:04       43 阅读