Linux IPC解析:匿名命名管道与共享内存

在这里插入图片描述

一.IPC机制介绍

IPC(Inter-Process Communication,进程间通信)是计算机系统中不同进程之间交换数据和同步操作的机制。由于现代计算机系统中,程序通常会由多个进程组成,这些进程可能需要相互通信以完成任务,因此IPC非常重要。

IPC主要功能:

  1. 数据交换:允许不同进程共享数据或传递信息。
  2. 同步:协调多个进程之间的操作,以避免竞态条件和资源冲突。
  3. 互斥:控制多个进程对共享资源的访问,确保同一时间只有一个进程能够访问资源

IPC主要机制:

  1. 管道(Pipes):匿名管道:用于相关进程之间的单向通信,如父子进程或兄弟进程。
    命名管道(FIFO):用于不相关进程之间的双向或单向通信,具有一个路径名,可以在不同的进程之间共享。
  2. 消息队列(Message Queues):允许进程以消息的形式发送和接收数据,消息可以按照队列的顺序进行传递。
  3. 共享内存(Shared Memory):允许多个进程映射同一块物理内存区域,从而实现高速的数据共享和通信。
  4. 信号量(Semaphores):用于实现进程间的同步和互斥,以控制对共享资源的访问。
  5. 套接字(Sockets):尽管最常用于网络通信,套接字也可以用于同一台计算机上的进程间通信。

二.匿名与命名管道

1.匿名管道

管道是进程间通信的一种机制,通常用于将一个进程的输出数据传递给另一个进程的输入。管道可以分为两种主要类型:匿名管道和命名管道。
管道原理简易演示图:
在这里插入图片描述
上图所示,我们就将通信信道建立好了。那么我们具体应该如何编码实现呢?
在这里插入图片描述
pipe函数介绍:

pipe()函数创建一个管道,该管道提供了一对文件描述符:一个用于读操作,另一个用于写操作。数据从写端流向读端。

返回值:

  • 成功:返回0。
  • 失败:返回-1,并将errno设置为错误代码。

下面我们写一段代码用匿名管道简单实现父子进程的通信:

#include <iostream>     // 包含输入输出流库
#include <cstdio>       // 包含标准输入输出库
#include <string>       // 包含C++字符串库
#include <cstring>      // 包含C字符串处理库
#include <cstdlib>      // 包含C标准库
#include <unistd.h>     // 包含POSIX操作系统API
#include <sys/types.h>  // 包含数据类型定义
#include <sys/wait.h>   // 包含进程等待函数

#define N 2             // 定义常量N为2
#define NUM 1024        // 定义常量NUM为1024,表示缓冲区大小

using namespace std;    // 使用标准命名空间

// Writer函数,向管道写数据
void Writer(int wfd)
{
   
   
    string s = "i am father";    // 定义字符串s
    pid_t self = getpid();       // 获取当前进程ID
    int number = 0;              // 定义一个计数器number,初始值为0

    char buffer[NUM];            // 定义缓冲区buffer
    while (true)                 // 无限循环
    {
   
   
        sleep(1);                // 休眠1秒

        buffer[0] = 0;           // 将缓冲区第一个位置置为0
        snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number++); // 格式化字符串并存入缓冲区
        cout << buffer << endl;  // 输出缓冲区内容

        write(wfd, buffer, strlen(buffer)); // 将缓冲区内容写入管道

        if(number>=5)            // 如果计数器number大于等于5,退出循环
            break;
    }
}

// Reader函数,从管道读数据
void Reader(int rfd)
{
   
   
    char buffer[NUM];            // 定义缓冲区buffer

    while(true)                  // 无限循环
    {
   
   
        buffer[0] = 0;           // 将缓冲区第一个位置置为0
        ssize_t n = read(rfd, buffer, sizeof(buffer)); // 从管道读取数据存入缓冲区
        if(n > 0)                // 如果读取到的数据长度大于0
        {
   
   
            buffer[n] = 0;       // 将缓冲区第n个位置置为0,表示字符串结束
            cout << "child get a message[" << getpid() << "]# " << buffer << endl; // 输出读取到的内容
        }
        else if(n == 0)          // 如果读取到的数据长度为0,表示管道已关闭
        {
   
   
            printf("child read file done!\n"); // 输出读取完成信息
            break;               // 退出循环
        }
        else break;              // 如果读取错误,退出循环
    }
}

int main()
{
   
   
    int pipefd[N] = {
   
   0};         // 定义一个数组pipefd,用于存放管道的文件描述符
    int n = pipe(pipefd);        // 创建管道,返回值n小于0表示创建失败
    if (n < 0)
        return 1;                // 如果创建管道失败,返回1

    pid_t id = fork();           // 创建子进程,返回值id小于0表示创建失败
    if (id < 0)
        return 2;                // 如果创建子进程失败,返回2

    if (id == 0)
    {
   
   
        // 子进程代码
        close(pipefd[1]);        // 关闭管道的写端

        // IPC代码
        Reader(pipefd[0]);       // 调用Reader函数,从管道读取数据

        close(pipefd[0]);        // 关闭管道的读端
        exit(0);                 // 退出子进程
    }
    // 父进程代码
    close(pipefd[0]);            // 关闭管道的读端
    // IPC代码
    Writer(pipefd[1]);           // 调用Writer函数,向管道写入数据
    close(pipefd[1]);            // 关闭管道的写端

    pid_t rid = waitpid(id, nullptr, 0); // 等待子进程结束
    if(rid < 0) return 3;        // 如果等待失败,返回3

    sleep(5);                    // 休眠5秒
    return 0;                    // 返回0,表示程序成功结束
}

在这里插入图片描述
运行起来后我们可以观察到,父进程每隔一秒格式化字符串输入缓冲区,并打印缓冲区内容,接着写进管道,这时子进程就能读到管道的数据,并将内容打印出来,父进程写五次后退出,并且关闭了写端,这是读端读到结尾后退出进程后被父进程等待回收
我们再来验证些特殊情况:

void Reader(int rfd)
{
   
   
    char buffer[NUM];            // 定义缓冲区buffer

    int _count =0;

    while(true)                  // 无限循环
    {
   
   
        buffer[0] = 0;           // 将缓冲区第一个位置置为0
        ssize_t n = read(rfd, buffer, sizeof(buffer)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aomnitrix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值