首页 > 其他分享 >消息传递机制(转载)

消息传递机制(转载)

时间:2024-12-29 14:58:56浏览次数:9  
标签:include int 管道 fd child 进程 消息传递 机制 转载

进程间的通信方式——pipe(管道)-CSDN博客

1.进程间通信

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

这里写图片描述

不同进程间的通信本质:进程之间可以看到一份公共资源;而提供这份资源的形式或者提供者不同,造成了通信方式不同,而 pipe就是提供这份公共资源的形式的一种。

2.匿名管道

2.1管道的创建

管道是由调用pipe函数来创建

#include <unistd.h>
int pipe (int fd[2]);//返回:成功返回0,出错返回-1 
//fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。

2.2管道如何实现进程间的通信

(1)父进程创建管道,得到两个⽂件描述符指向管道的两端

(2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。

(3)父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。
这里写图片描述

2.3如和用代码实现管道通信

#include <stdio.h>  
#include <unistd.h>  
#include <string.h>  
#include <errno.h>  
int main()  
{  
    int fd[2];  
    int ret = pipe(fd);  
    if (ret == -1)  
    {  
        perror(”pipe error\n”);  
        return 1;  
    }  
    pid_t id = fork();  
    if (id == 0)  
    {//child  
        int i = 0;  
        close(fd[0]);  
        char *child = “I am  child!”;  
        while (i<5)  
        {  
            write(fd[1], child, strlen(child) + 1);  
            sleep(2);  
            i++;  
        }  
    }  
    else if (id>0)  
    {//father  
        close(fd[1]);  
        char msg[100];  
        int j = 0;  
        while (j<5)  
        {  
            memset(msg,’\0’,sizeof(msg));  
            ssize_t s = read(fd[0], msg, sizeof(msg));  
            if (s>0)  
            {  
                msg[s - 1] = ’\0’;  
            }  
            printf(”%s\n”, msg);  
            j++;  
        }  
    }  
    else  
    {//error  
        perror(”fork error\n”);  
        return 2;  
    }  
    return  0;  
}  

这里写图片描述

2.4管道读取数据的四种的情况

(1)读端不读,写端一直写
这里写图片描述
(2)写端不写,但是读端一直读
这里写图片描述

(3)读端一直读,且fd[0]保持打开,而写端写了一部分数据不写了,并且关闭fd[1]。
这里写图片描述

如果一个管道读端一直在读数据,而管道写端的引⽤计数⼤于0决定管道是否会堵塞,引用计数大于0,只读不写会导致管道堵塞。

(4)读端读了一部分数据,不读了且关闭fd[0],写端一直在写且f[1]还保持打开状态。

这里写图片描述

#include <stdio.h>  
#include <unistd.h>  
#include <string.h>  
#include <errno.h>  
int main()  
{  
    int fd[2];  
    int ret = pipe(fd);  
    if (ret == -1)  
    {  
        perror(”pipe error\n”);  
        return 1;  
    }  
    pid_t id = fork();  
    if (id == 0)  
    {//child  
        int i = 0;  
        close(fd[0]);  
        char *child = “I am  child!”;  
        while (i<10)  
        {  
            write(fd[1], child, strlen(child) + 1);  
            sleep(2);  
            i++;  
        }  
    }  
    else if (id>0)  
    {//father  
        close(fd[1]);  
        char msg[100];  
        int status = 0;  
        int j = 0;  
        while (j<5)  
        {  
            memset(msg, ’\0’, sizeof(msg));  
            ssize_t s = read(fd[0], msg, sizeof(msg));  
            if (s>0)  
            {  
                msg[s - 1] = ’\0’;  
            }  
            printf(”%s  %d\n”, msg, j);  
            j++;  
        }  
        //写方还在继续,而读方已经关闭它的读端  
        close(fd[0]);  
        pid_t ret = waitpid(id, &status, 0);  
        printf(”exitsingle(%d),exit(%d)\n”, status & 0xff, (status >> 8) & 0xff);  
        //低八位存放该子进程退出时是否收到信号  
        //此低八位子进程正常退出时,退出码是多少  
    }  
    else  
    {//error  
        perror(”fork error\n”);  
        return 2;  
    }  
    return  0;  
}  
运行结果:使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。总结:
如果一个管道的写端一直在写,而读端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只写不读再次调用write会导致管道堵塞;
如果一个管道的读端一直在读,而写端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只读不写再次调用read会导致管道堵塞;
而当他们的引用计数等于0时,只写不读会导致写端的进程收到一个SIGPIPE信号,导致进程终止,只写不读会导致read返回0,就像读到⽂件末尾⼀样。

2.5管道特点

1.管道只允许具有血缘关系的进程间通信,如父子进程间的通信。

2.管道只允许单向通信。

3.管道内部保证同步机制,从而保证访问数据的一致性。

4.面向字节流

5.管道随进程,进程在管道在,进程消失管道对应的端口也关闭,两个进程都消失管道也消失。

2.6管道容量大小

测试管道容量大小只需要将写端一直写,读端不读且不关闭fd[0],即可。
测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe error\n");
        return 1;
    }
    pid_t id = fork();
    if (id == 0)
    {//child
        int i = 0;
        close(fd[0]);
        char *child = "I am  child!";
        while (++i)
        {
            write(fd[1], child, strlen(child) + 1);
            printf("pipe capacity: %d\n", i*(strlen(child) + 1));
        }
        close(fd[1]);
    }
    else if (id>0)
    {//father
        close(fd[1]);
        waitpid(id, NULL, 0);
    }
    else
    {//error
        perror("fork error\n");
        return 2;
    }
    return  0;
}

可以看到写到65520之后管道堵塞了,而65536即为64K大小即为管道的容量(由于代码问题,少统计一次数据)。

这里写图片描述

进程间通信方式———信号量(Semaphore)
http://blog.csdn.net/skyroben/article/details/72513985

进程间通信方式———消息队列
http://blog.csdn.net/skyroben/article/details/72520501

进程间通信方式——共享内存
http://blog.csdn.net/skyroben/article/details/72625028

标签:include,int,管道,fd,child,进程,消息传递,机制,转载
From: https://www.cnblogs.com/T0fV404/p/18638847

相关文章

  • MD语法笔记(转载)
    [Markdown+Typora/VSCode超全教程]给大一新生安利的文本神器Sakiyary2022/7/16[Markdown+Typora/VSCode超全教程]给大一新生安利的文本神器!_哔哩哔哩_bilibili......
  • Z3求解器(转载)
    title:Z3求解器date:2024/12/2717:31:00toc:truecategories:REVERSE以下全部摘自别人,这个工具我懒得看官方文档,等需要时来看吧.Z3简介Z3是一个微软出品的开源约束求解器,能够解决很多种情况下的给定部分约束条件寻求一组满足条件的解的问题(可以简单理解为解方程......
  • RocketMQ 消息顺序与事务机制详解
    目录一、简介二、RocketMQ架构概述三、RocketMQ消息流转过程四、RocketMQ消息顺序与事务五、RocketMQ高可用性与扩展性六、RocketMQ应用场景七、总结一、简介RocketMQ是一款高吞吐量、高可扩展性的分布式消息中间件,由阿里巴巴开源,并已成为Apache的顶级项目......
  • Yolo11改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用
    摘要论文介绍本文介绍了一种名为DynamicHead的模块,该模块旨在通过注意力机制统一目标检测头部,以提升目标检测的性能。论文详细阐述了DynamicHead的工作原理,并通过实验证明了其在COCO基准测试上的有效性和效率。创新点DynamicHead模块的创新之处在于它首次尝试在一个统一......
  • 【Elasticsearch】数据分布与路由机制
    ......
  • 高级java每日一道面试题-2024年12月27日-并发篇-锁的优化机制了解吗 ?
    如果有遗漏,评论区告诉我进行补充面试官:锁的优化机制了解吗?我回答:在Java高级面试中,锁的优化机制是一个重要且常见的考点。以下是对Java锁优化机制的详细解释:一、锁的基本概念锁是多线程编程中至关重要的同步机制,用于确保线程间共享数据的正确性。然而,使用锁也会引......
  • 游戏机制与关卡分析:生化危机4村庄战
    主角来到村庄,1、怪物与BOSS村民按照固定脚本开始慢速巡逻,走来走去。村民拥有视力,以及听力,能感知到主角的活动。当觉察到主角后,就会切换到快速移动状态,接近主角后切换到慢速移动状态,逐渐逼近主角。如果从主角背后接近,则会降低速度。此时的村民以近战为主,空手、叉子、斧子......
  • C# 中的委托与事件:实现灵活的回调机制
    C#中的委托(Delegate)和事件(Event)。委托和事件是C#中非常重要的特性,它们允许你实现回调机制和发布-订阅模式,从而提高代码的灵活性和解耦程度。通过使用委托和事件,你可以编写更加模块化和可扩展的应用程序。以下是一篇关于C#中委托和事件的文章。引言委托(Delegate)和事件(Even......
  • 【WPF】WPF 双向绑定中的 SelectedItem 与 ViewModel 属性更新机制详解
     在WPF开发中,ListBox等控件常用于显示绑定的数据集合,其中ItemsSource绑定的数据源,在没有显式设置 Mode 属性时,默认为单向绑定,它将数据源集合的内容传递给 ListBox,但不会反向更新数据源。而SelectedItem ,默认情况下它的绑定是双向的。这意味着当用户在 ListBox 中......
  • 深入理解 MySQL 数据库的锁机制与索引使用
    1.请说说MySQL数据库的锁?MySQL数据库中的锁机制是用来管理对数据库资源的并发访问,确保数据的一致性和完整性。不同的存储引擎可能有不同的锁实现。以下是MySQL中主要的锁类型:表级锁(Table-LevelLocking):适用于MyISAM、MEMORY等存储引擎。包括读锁(共享锁)和写锁(排他......