当前位置: 首页 > wzjs >正文

网站公司名称大全南昌大型网站建设公司

网站公司名称大全,南昌大型网站建设公司,深圳网站建设行吗,创意设计图片大全目录 前言: 一、 什么是命名管道 二、如何创建命名管道 三、命名管道的读写端 四、命名管道的阻塞问题 1. 阻塞模式(默认行为) 2. 非阻塞模式(O_NONBLOCK) 总结 前言: 我们昨天给大家模拟实现了一…

目录

前言:

一、 什么是命名管道

二、如何创建命名管道

三、命名管道的读写端

四、命名管道的阻塞问题

1. 阻塞模式(默认行为)

2. 非阻塞模式(O_NONBLOCK)

总结


前言:

我们昨天给大家模拟实现了一个匿名管道的经典应用场景:进程池。

今天,我将会为大家带来管道中的另外一种管道:命名管道(FIFO)

其作为其中一种经典的通信方式,既有管道(pipe)的简单性,又突破了匿名管道只能用于父子进程间通信的限制。本文将全面深入地介绍命名管道的原理、使用方法和实际应用场景。希望能够对大家有所帮助。

一、 什么是命名管道

先简单回顾一下我们前几节所写的内容,我们讲了匿名管道的有关知识,知道一旦创建管道的进程终止,管道就不复存在。也知道匿名管道通常是依靠父子进程的写时拷贝机制,看见同一份资源而实现进程间通信的。

所以匿名管道有一个十分明显的特性:只能用于父子进程或有共同祖先的进程间通信

如果两个进程之间不具备任何血缘关系,那我们又应该怎么才能让他俩看见同一份资源,实现进程间通信呢?

答案就是命名管道!

命名管道(FIFO, First In First Out)是一种特殊的文件类型,它在文件系统中有一个名称。最关键的是,由于有名字,是一个文件,我们就知道他的路径,而具有路径+文件名,就具有唯一性,任何进程就都能找到这个文件。因此不相关的进程可以通过这个名称访问同一个FIFO进行通信。

我们普通的文件,既有内核级缓冲区,也会涉及到从缓冲区把数据刷新的到磁盘的操作。

但是命名管道是特殊的文件,我们可以通过mkfifo指令在linux中创建一个命名管道文件:

可以看到,该文件的前缀是p。 (p的含义就是只使用内核级缓冲区,而不做刷新操作)。

二、如何创建命名管道

在shell中,可以使用mkfifo命令创建命名管道。而在编程中, 我们可以使用mkfifo()函数创建命名管道:

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

这个函数的本质是创建一个fifo文件,所以第一个参数,就类似与opne函数的写操作,是该文件的一个路径信息,而mode参数也是一样的,表示这个fifo文件的权限,同样受umask限制。

而创建该fifo文件后,我们就可以调用open函数打开这个管道,进行读写。

使用完毕后应关闭文件描述符:close(fd);

而要删除FIFO文件,可以使用unlink()

由于读写肯定是两个进程之间的事情,所以我们接下来就来模拟一下,分别实现两个进程,进行进程间通信!

三、命名管道的读写端

我们接下来就来实现一下读端进程与写端进程,随后在两个bash中分别调用,进行信息传递。

首先就是读端。

我们可以封装一个Init类,在构造函数中自动创建一个管道,在他的析构函数中自动关闭管道,随后创建一个全局变量Init init,之后,我们就可以在包含这个hpp文件的代码中使用这个全局变量


 

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>class Init
{public:Init(){umask(0);int n = ::mkfifo("fifo", 0666);if(n<0){std::cerr<<"mkfifo error"<<std::endl;return;}std::cout<<"mkfifo success"<<std::endl;}~Init(){int n =::unlink("fifo");if(n<0){std::cerr<<"unlink error"<<std::endl;return;}std::cout<<"unlink success"<<std::endl;}
};Init init;

随后,我们可以继续封装一个Reader类,负责实现我们从管道里读取数据的一系列接口:打开管道,读取信息,关闭管道这三个接口:


class Reader
{public:Reader(int fd=-1):_fd(fd){}void OpneFifo()//打开一个命名管道{_fd=::open("fifo",O_RDONLY);if(_fd<0){std::cerr<<"open error"<<std::endl;}}int ReadPipe(std::string *out)//这是一个输出型参数,我们把读到的数据传给此参数{char buffer[1024];ssize_t n=::read(_fd,buffer,sizeof(buffer)-1);if(n>0){buffer[n]='\0';*out=buffer;}return n;}void ClosePipe(){::close(_fd);}private:int _fd;
};

都是比较基础的一些操作,我们之前曾多次使用,所以这里不再详细赘述原因。

这里只是Reader.hpp文件,我们需要创建一个进程,自然需要在Reader.cc中创建main函数,构造结构体进行读取:
 

#include"reader.hpp"int main()
{Reader reader;reader.OpneFifo();std::string message;while (true){if (reader.ReadPipe(&message) > 0){std::cout << "client Say# " << message << std::endl;}else{break;}}reader.ClosePipe();return 0;
}

写端代码是一样的结构,除了少了一个ini全局变量,而这个init其实也可以在写端声明,读写端谁先打开创建管道其实没有区别(这点我们会在后面说明)

所以写端代码如下:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>class Writer
{public:Writer(int fd=-1):_fd(fd){}void OpneFifo()//打开一个命名管道{_fd=::open("fifo",O_WRONLY);if(_fd<0){std::cerr<<"open error"<<std::endl;}}int WritePipe(const std::string &in)//这是一个输入型参数,我们把此数据写入管道中{return ::write(_fd,in.c_str(),in.size());}void ClosePipe(){::close(_fd);}private:int _fd;
};

 

#include"writer.hpp"int main()
{Writer writer;writer.OpneFifo();std::string message;while(true){std::cout<<"请输入#";std::getline(std::cin,message);writer.WritePipe(message);}writer.ClosePipe();return 0;
}

分别编译代码并运行,我们可以看见我们的两个进程,writer与reader两个没有血缘关系的进程,已经实现了通信 

当然,这样是我们的单向通信。如果想要实现两个进程之间的双向通信,我们可以创建两个管道。随后在两个进程的while循环中进行循环就行了。 

四、命名管道的阻塞问题

命名管道的阻塞行为完全由 open() 时的 mode 参数控制,不同组合会导致截然不同的行为

1. 阻塞模式(默认行为)

(1) O_RDONLY(仅读打开)

  • 行为

    • 读进程会在 open() 处阻塞,直到有写进程以 O_WRONLY 打开同一 FIFO

    • 这是典型的"读端等待写端"场景。

  • 用途

    • 确保写端就绪后再开始读取,避免读取空管道。

(2) O_WRONLY(仅写打开)

  • 行为

    • 写进程会在 open() 处阻塞,直到有读进程以 O_RDONLY 打开同一 FIFO

    • 这是典型的"写端等待读端"场景。

  • 用途

    • 确保读端就绪后再开始写入,避免写入无读者的管道(否则会触发 SIGPIPE)。

值得一提的是潜在死锁的问题,若两个进程以相反顺序打开:

// 进程A(读端)
int fd = open("fifo", O_RDONLY); // 阻塞等写端// 进程B(写端)
int fd = open("fifo", O_WRONLY); // 阻塞等读端

结果就是:互相等待,形成死锁


2. 非阻塞模式(O_NONBLOCK

(1) O_RDONLY | O_NONBLOCK(非阻塞读打开)

  • 行为

    • open() 立即成功返回,即使没有写端打开。

    • 后续 read() 的行为:

      • 若管道为空:返回 -1errno=EAGAIN

      • 若所有写端关闭:返回 0(EOF)。

  • 用途

    • 需要轮询检查数据的场景(如事件驱动模型)。

(2) O_WRONLY | O_NONBLOCK(非阻塞写打开)

  • 行为

    • 如果没有读端打开:

      • open() 立即失败,返回 -1errno=ENXIO

    • 如果有读端打开:

      • open() 成功,后续 write() 的行为:

        • 若管道缓冲区满:返回 -1errno=EAGAIN

        • 若所有读端关闭:触发 SIGPIPE,返回 -1errno=EPIPE

  • 用途

    • 避免写进程因无读端而无限阻塞。


总结

本篇文章为大家介绍了一下命名管道的相关概念与性质,并为大家提供代码,实现了两个没有任何关系的进程之间的通信。

希望对大家有所帮助!!


文章转载自:

http://cGmGz6AJ.pmLgr.cn
http://tRZIdauF.pmLgr.cn
http://lfHL0B75.pmLgr.cn
http://00smOvaB.pmLgr.cn
http://KKYC927r.pmLgr.cn
http://wN0vT5p0.pmLgr.cn
http://ikmCnw98.pmLgr.cn
http://oGbgcwVO.pmLgr.cn
http://TXxkV0V9.pmLgr.cn
http://Ocp0Tnvv.pmLgr.cn
http://PtbxRQBx.pmLgr.cn
http://19pk85Qp.pmLgr.cn
http://5nD3d3s7.pmLgr.cn
http://w7OzaWRU.pmLgr.cn
http://QJpR9rG7.pmLgr.cn
http://KILWBWrj.pmLgr.cn
http://WllKejNE.pmLgr.cn
http://atGx2Id3.pmLgr.cn
http://pxtOxJ7k.pmLgr.cn
http://OVR8VOeO.pmLgr.cn
http://BsDYbQRQ.pmLgr.cn
http://tuB5GQdb.pmLgr.cn
http://UDsF47u7.pmLgr.cn
http://lPo350Vu.pmLgr.cn
http://j5ZkA9iv.pmLgr.cn
http://4seL4CBe.pmLgr.cn
http://K9QbTAXm.pmLgr.cn
http://hfBbqoSg.pmLgr.cn
http://Q75EWnP3.pmLgr.cn
http://QOuWwVMg.pmLgr.cn
http://www.dtcms.com/wzjs/747359.html

相关文章:

  • 广州金融网站设计wordpress 主题学习
  • 利用vs做网站网站建设课程
  • 不懂编程如何做网站网站建设的人员预期
  • 做网站 需要 域名 空间网站演示程序
  • 房子装修网站医学分类手机网站模版
  • 个性化网站模板昭通商城网站建设
  • 百度安装app下载免费湖南网站seo营销
  • 国际网站建设做网站的图片大全
  • asp 网站运行在线商城系统平台
  • 做网站注意哪些室内设计学校全国排名
  • 电子及商务网站建设报告桂林北站改造
  • 海外购物网站哪个最好黄冈网站推广在线
  • 做任务网站排行榜wordpress 地址设置方法
  • 管局备案网站古风ppt模板免费下载
  • 网站建设冷色调开发小程序费用一览表
  • 规划建立一个网站 项目wordpress指定上传目录
  • 怎样建设一个韩国网站南京seo关键词优化预订
  • 济源城乡建设局网站网站开发2019
  • 开通网站的请示网站怎么进行网络推广
  • 无忧网站建设更改wordpress程序站点网址
  • 建设部考试中心网站北京楼市暴跌
  • 2013电子商务网站建设考试试卷厦门seo网站排名优化
  • 漫画网站开发辽源商城网站建设
  • 延安网站设计河北公司网站开发
  • 泰安网络营销优化关键词技巧
  • 各大公司开源网站做网站交钱后以后还要教吗
  • 企业为什么做网站wordpress修改背景
  • 网站图怎么做会高清图片wordpress双语言设置
  • 找私人做网站江西城乡建设培训中心网站
  • 优秀网站模板欣赏怎样购买网站