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

茂名建设中专学校网站创业网站建设方案项目书

茂名建设中专学校网站,创业网站建设方案项目书,学校类网站特点,一站式服务logo设计参考博客#xff1a;https://blog.csdn.net/sjsjnsjnn/article/details/125864580 一、进程间通讯介绍 1.1 进程间通讯的概念 进程通信#xff08;Interprocess communication#xff09;#xff0c;简称#xff1a;IPC 本来进程之间是相互独立的。但是由于不同的进程…参考博客https://blog.csdn.net/sjsjnsjnn/article/details/125864580 一、进程间通讯介绍 1.1 进程间通讯的概念 进程通信Interprocess communication简称IPC 本来进程之间是相互独立的。但是由于不同的进程之间可能要共享某些信息所以就必须要有通讯来实现进程间的互斥和同步。比如说共享同一块内存、管道、消息队列、信号量等等就是实现这一过程的手段相当于移动公司在打电话的作用。 1.2 进程间通讯的目的 数据传输一个进程需要将它的数据发送给另一个进程资源共享多个进程之间共享同样的资源。通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变 1.3 进程间通信的前提 进程间通信的前提本质由操作系统参与提供一份所有通信进行都能看到的公共资源两个或多个进程相互通信必须先看到一份公共的资源这里的所谓的资源是属于操作系统的就是一段内存可能以文件的方式提供、可能以队列的方式提供也有可能提供的就是原始内存块这也就是通信方式有很多种的原因 1.4 进程间通信的分类 管道 匿名管道pipe命名管道 System V IPC System V 消息队列System V 共享内存System V 信号量 POSIX IPC 消息队列共享内存信号量互斥量条件变量读写锁 二、管道通讯 2.1 管道的概念 管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 比如下面的命令我们通过管道连接了cat test.c和wc -l两个命令本质是两个进程 cat test.c | wc -l运行的结果如下统计了test.c文件的行数(wc)并且将对应的结果输出了出来(cat)这里执行的顺序为从右到左先执行wc -l 2.2 匿名管道 2.2.1 基本原理 匿名管道用于进程间通信且仅限于父子进程之间的通信。 我们知道进程的PCB中包含了一个指针数组 struct file_struct它是用来描述并组织文件的。父进程和子进程均有这个指针数组因为子进程是父进程的模板其代码和数据是一样的 打开一个文件时其实是将文件加载到内核中内核将会以结构体(struct file)的形式将文件的相关属性、文件操作的指针集合即对应的底层IO设备的调用方法等 当父进程进行数据写入时例如写入“hello Linux”数据是先被写入到用户级缓冲区经由系统调用函数又写入到了内核缓冲区在进程结束或其他的操作下才被写到了对应的设备中 如果数据在写入设备之前“hello Linux”是在内核缓冲区的因为子进程和父进程是同时指向这个文件的所以子进程是能够看到这个数据的并且可以对其操作 简单来说父进程向文件写入数据时不直接写入对应的设备中而是将数据暂存在内核缓冲区中交给子进程来处理 所以这种基于文件的方式就叫做管道 2.2.2 管道的创建步骤 在创建匿名管道实现父子进程间通信的过程中需要pipe函数和fork函数搭配使用具体步骤如下 匿名管道属于单向通信意味着父子进程只有一个端是打开的实现父子通信的时候就需要根据自己的想要实现的情况关闭对应的文件描述符 pipe函数 #include unistd.h int pipe(int pipefd[2]);函数的参数是两个文件的描述符是输出型参数 pipefd[0]读管道 — 对应的文件描述符是3pipefd[1]写管道 — 对应的文件描述符是4 返回值成功返回0失败返回-1 2.2.3 匿名管道通讯 下面的代码通过使用fork和pipe函数实现父子进程之间的通讯其中父进程用于读取数据子进程用于写入数据由于管道是单向通讯的因此需要关闭管道的另一端即父进程关闭写端子进程关闭读端 void test1(){int pipe_fd[2];memset(pipe_fd,0,sizeof(pipe_fd));int ret pipe(pipe_fd);if(ret 0 ){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if(ret 0){ //子进程close(pipe_fd[0]); //关闭子进程读端for(int i 1;i10;i){std::string msg hello from child process : std::to_string(i) times;write(pipe_fd[1],msg.c_str(),msg.size());sleep(1);}exit(0);}close(pipe_fd[1]); //关闭父进程写端char buffer[1024];memset(buffer,0,sizeof(buffer));while(1){ssize_t s read(pipe_fd[0],buffer,sizeof(buffer));if(s 0){std::cout read finished ! std::endl;break; }else{buffer[s] \0;std::cout read from child process : buffer std::endl;}} }可以发现管道的读写端的文件描述符为34其中0,12通常是输入流、输出流和错误流通过打印结果可以发现父子进程成功通讯了 2.2.4 匿名管道通讯的特点 五个特点 管道仅限父子通讯只能单向通讯管道提供流式服务管道自带同步与互斥机制进程退出管道随之释放因此管道的生命周期随进程如果需要双向通讯则需要建立两个管道 四个情况 读端不读或者读得慢写端要等待读端读端关闭写端收到SIGPIPE信号后终止写端不写或者写得慢读端要等待写端写端关闭读端读到EOF后退出 2.2.5 字节流通讯 字节流的特征就是没有边界每次读取指定的字节我们发送数据的时候是先把数据写到内核缓冲区中读取的时候也是从内核缓冲区读取指定的字节因此如果写端慢了那么读取的数据会重合在一起如下面的程序所示 void test1(){int pipe_fd[2];memset(pipe_fd,0,sizeof(pipe_fd));int ret pipe(pipe_fd);if(ret 0 ){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if(ret 0){ //子进程close(pipe_fd[0]); //关闭子进程读端for(int i 1;i10;i){std::string msg hello from child process : std::to_string(i) times;write(pipe_fd[1],msg.c_str(),msg.size());sleep(1);}exit(0);}close(pipe_fd[1]); //关闭父进程写端char buffer[1024];memset(buffer,0,sizeof(buffer));while(1){sleep(10);ssize_t s read(pipe_fd[0],buffer,sizeof(buffer));if(s 0){std::cout read finished ! std::endl;break; }else{buffer[s] \0;std::cout read from child process : buffer std::endl;}} }可以发现读取的数据全都合并在一起了因为我们指定读取的字节数较大 2.2.6 同步机制 内核的缓冲区是有大小限制的下面我们不断发送数据到内核缓冲区到了65536字节后就发送不了了此时阻塞了进程 void test2(){int pipe_fd[2];memset(pipe_fd,0,sizeof(pipe_fd));int ret pipe(pipe_fd);if(ret 0 ){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if(ret 0){ //子进程close(pipe_fd[0]); //关闭子进程读端int writedBytes 0;for(int i 1;i10000000;i){write(pipe_fd[1],a,1);writedBytes ;std::cout child process send msg: a ,writed Bytes writedBytes std::endl;}exit(0);}close(pipe_fd[1]); //关闭父进程写端char buffer[1024];memset(buffer,0,sizeof(buffer));while(1){sleep(1);} } 管道通讯自带同步机制和互斥机制也就是发送端和接收端看到的数据是一致的并且同时只有一段可以读或者写下面的程序在内核缓冲区写满了以后尝试读取数据发现只有读取了一些数据之后才能继续往内核写入数据而不是读取一个字节可以写入一个字节 void test3() {int pipe_fd[2];memset(pipe_fd,0,sizeof(pipe_fd));int ret pipe(pipe_fd);if(ret 0 ){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if(ret 0){ //子进程close(pipe_fd[0]); //关闭子进程读端int writedBytes 0;for(int i 1;i10000000;i){write(pipe_fd[1],a,1);writedBytes ;std::cout child process send msg: a ,writed Bytes writedBytes std::endl;}exit(0);}close(pipe_fd[1]); //关闭父进程写端sleep(5);while(1){char c 0;read(pipe_fd[0],c,1);std::cout read : c std::endl;sleep(1);} }读取部分数据后才会继续写入读端太慢会导致写端等待读端 void test3() {int pipe_fd[2];memset(pipe_fd,0,sizeof(pipe_fd));int ret pipe(pipe_fd);if(ret 0 ){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if(ret 0){ //子进程close(pipe_fd[0]); //关闭子进程读端int writedBytes 0;for(int i 1;i10000000;i){write(pipe_fd[1],a,1);writedBytes ;std::cout child process send msg: a ,writed Bytes writedBytes std::endl;}exit(0);}close(pipe_fd[1]); //关闭父进程写端sleep(5);char buffer[1024];memset(buffer,0,sizeof(buffer));int readBytes 0;while(1){char c 0;ssize_t s read(pipe_fd[0],buffer,sizeof(buffer));buffer[s] \0;std::cout read : buffer std::endl;std::cout read bytes readBytes std::endl;sleep(1);readBytes s;} }2.2.7 写端关闭 写端关闭那么读端会读到EOF后自动退出比如下面的程序我们让读进程先休眠一会然后写进程写了一些数据后退出那么读进程读到EOF后也就退出了 void test4() {int pipe_fd[2];memset(pipe_fd, 0, sizeof(pipe_fd));int ret pipe(pipe_fd);if (ret 0){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if (ret 0){ // 子进程close(pipe_fd[0]); // 关闭子进程读端for (int i 1; i 10; i){write(pipe_fd[1], abcdefg, 7);}exit(0);}sleep(5);close(pipe_fd[1]); // 关闭父进程写端char buffer[1024];memset(buffer, 0, sizeof(buffer));int readBytes 0;while (1){char c 0;ssize_t s read(pipe_fd[0], buffer, sizeof(buffer));if (s 0){std::cout read finished ! std::endl;break;}buffer[s] \0;readBytes s;std::cout read : buffer std::endl;std::cout read bytes readBytes std::endl;sleep(1);} }2.2.8 读端关闭 读端关闭写段会收到SIGPIPE信号然后中断进程当我们的读端关闭写端还在写入在操作系统的层面上严重不合理这本质上就是在浪费操作系统的资源所以操作系统在遇到这样的情况下会将子进程杀掉发送13号信号—SIGPIPE 下面的shell脚本用于持续跟踪测试进程 while :; do ps axj | grep pipe_process | grep -v grep; sleep 1; echo ####################; done;可以发现子进程退出后父进程随之也退出了 这里我们添加上父进程等待子进程也就是waitpid然后输出对应的信号值可以发现退出后的信号值为13对应的是SIGPIPE void test5() {int pipe_fd[2];memset(pipe_fd, 0, sizeof(pipe_fd));int ret pipe(pipe_fd);if (ret 0){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if (ret 0){ // 子进程close(pipe_fd[0]); // 关闭子进程读端for (int i 1; i 10; i){write(pipe_fd[1], abcdefg, 7);sleep(1);}exit(0);}close(pipe_fd[1]); // 关闭父进程写端char buffer[7];memset(buffer, 0, sizeof(buffer));int readBytes 0;while (1){char c 0;ssize_t s read(pipe_fd[0], buffer, sizeof(buffer));if (s 0){std::cout read finished ! std::endl;break;}buffer[s] \0;std::cout read : buffer std::endl;readBytes s;std::cout read bytes readBytes std::endl;sleep(2);close(pipe_fd[0]);int status 0;waitpid(-1, status, 0);printf(exit code: %d\n,(status 8) 0xFF);printf(exit signal: %d\n,status 0x7F);} }查询对应的信号符合预期 kill -l2.2.9 非阻塞管道 int pipe2(int pipefd[2], int flags);可以通过pip2函数设置管道通讯的阻塞与非阻塞可以通过设置O_NONBLOCK标志为非阻塞默认为阻塞或者传入0 当没有数据可读时 O_NONBLOCK disableread调用阻塞即进程暂停执行一直等到有数据来到为止。O_NONBLOCK enableread调用返回-1errno值为EAGAIN。 当管道满的时候 O_NONBLOCK disable write调用阻塞直到有进程读走数据O_NONBLOCK enable调用返回-1errno值为EAGAIN如果所有管道写端对应的文件描述符被关闭则read返回0如果所有管道读端对应的文件描述符被关闭则write操作会产生信号SIGPIPE,进而可能导致write进程退出当要写入的数据量不大于PIPE_BUF时linux将保证写入的原子性。当要写入的数据量大于PIPE_BUF时linux将不再保证写入的原子性。 2.2.9.1 非阻塞写入满了 下面的程序演示非阻塞管道写端在内核写入满了以后的返回值 void test6(){int pipe_fd[2];memset(pipe_fd, 0, sizeof(pipe_fd));int ret pipe2(pipe_fd,O_NONBLOCK);if (ret 0){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if (ret 0){ // 子进程close(pipe_fd[0]); // 关闭子进程读端int writedBytes 0;for (int i 1; i 10000000; i){int ret write(pipe_fd[1], a, 1);if(ret -1 errno EAGAIN){std::cout errno: EAGAIN ! std::endl;sleep(1);continue;}writedBytes;std::cout child process send msg: a ,writed Bytes writedBytes std::endl;}exit(0);}close(pipe_fd[1]); // 关闭父进程写端int readBytes 0;while (1){sleep(1);} } 2.2.9.2 非阻塞无数据可读 下面的程序演示非阻塞管道读取无数据可读的返回值 void test7(){int pipe_fd[2];memset(pipe_fd, 0, sizeof(pipe_fd));int ret pipe2(pipe_fd,O_NONBLOCK);if (ret 0){std::cout error: strerror(ret) std::endl;return;}std::cout pipe_fd[0] pipe_fd[0] std::endl;std::cout pipe_fd[1] pipe_fd[1] std::endl;ret fork();if (ret 0){ // 子进程close(pipe_fd[0]); // 关闭子进程读端sleep(60);}close(pipe_fd[1]); // 关闭父进程写端int readBytes 0;char buffer[1024] {0};while (1){ssize_t s read(pipe_fd[0],buffer, sizeof(buffer));if(s -1 errno EAGAIN){std::cout errno EAGAIN ! std::endl;sleep(1);continue;}} } 2.3 命名管道 2.3.1 命名管道的概念 匿名管道应用的一个限制就是只能在具有共同祖先具有亲缘关系的进程间通信。如果我们想在不相关的进程之间交换数据可以使用FIFO文件来做这项工作它经常被称为命名管道。 命名管道是一种特殊类型的文件 2.3.2 命名管道的创建 2.3.2.1 命令行创建 可以通过命令行创建命名管道使用mkfifo指令 创建管道之后可以使用cat指令读取数据使用echo指令写入数据 2.3.2.2 代码创建 使用mkfifo函数可以创建一个命名管道 函数原型 int mkfifo(const char *pathname, mode_t mode);pathname表示你要创建的命名管道文件 如果pathname是以文件的方式给出默认在当前的路径下创建如果pathname是以某个路径的方式给出将会在这个路径下创建 mode表示给创建的命名管道设置权限 我们在设置权限时例如0666权限它会受到系统的umask文件默认掩码的影响实际创建出来是(mode ~umask)0664;所以想要正确的得到自己设置的权限0666我们需要将文件默认掩码设置为0 返回值命名管道创建成功返回0失败返回-1 #define MY_FIFO myfifoint main(int argc,char* argv[]) {umask(0);int ret mkfifo(MY_FIFO,0666);if(ret 0){perror(mkfifo);return 1;}return 0; }2.3.3 使用命名管道通讯 我们使用CS模型在服务端创建命名管道同时服务端不断读取数据客户端发送数据使用阻塞管道当没有数据可读服务端持续阻塞等待客户端的数据 server #includeiostream #includesys/stat.h #includeunistd.h #includefcntl.h #includecstring#define MY_FIFO fifo int main(){umask(0);int ret mkfifo(MY_FIFO,0666);if(ret 0){perror(mkfifo);return 1;}int fd open(MY_FIFO,O_RDONLY);//只读模式if(fd 0){perror(open);return 1;}while(1){char buffer[1024];memset(buffer,0,sizeof(buffer));ssize_t len read(fd,buffer,sizeof(buffer) - 1);if(len 0){std::cout read fifo finished ! std::endl;break;}else if(len 0){buffer[len] \0;std::cout read from client : buffer std::endl;}else{perror(open);break;}}close(fd);return 0; }client #includeiostream #includesys/stat.h #includeunistd.h #includefcntl.h #includecstring#define MY_FIFO fifo int main(){int fd open(MY_FIFO,O_WRONLY);//写入模式if(fd 0){perror(open);return 1;}while(1){std::string str;std::cout Please enter message :;std::cin str;ssize_t len write(fd,str.c_str(),str.size());if(len 0){perror(write);break;}}close(fd);return 0; }2.4 管道的总结 管道 管道分为匿名管道和命名管道 管道通信方式的中间介质是文件通常称这种文件为管道文件 匿名管道:管道是半双工的数据只能单向通信需要双方通信时需要建立起两个管道只能用于父子进程或者兄弟进程之间具有亲缘关系的进程。 命名管道不同于匿名管道之处在于它提供一个路径名与之关联以FIFO的文件形式存在于文件系统中。这样即使与FIFO的创建进程不存在亲缘关系的进程只要可以访问该路径就能够彼此通过FIFO相互通信 利用系统调用pipe()创建一个无名管道文件通常称为无名管道或PIPE利用系统调用mkfifo()创建一个命名管道文件通常称为有名管道或FIFO。 PIPE是一种非永久性的管道通信机构当它访问的进程全部终止时它也将随之被撤消。 FIFO是一种永久的管道通信机构它可以弥补PIPE的不足。管道文件被创建后使用open()将文件进行打开然后便可对它进行读写操作通过系统调用write()和read()来实现。通信完毕后可使用close()将管道文件关闭。 匿名管道的文件是内存中的特殊文件而且是不可见的命名管道的文件是硬盘上的设备文件是可见的。 更多资料https://github.com/0voice
http://www.zqtcl.cn/news/627726/

相关文章:

  • 网站建设公司哪个好一点最近一周的热点新闻
  • 做最优秀的自己的视频网站佛山搜索引擎优化
  • 六盘水市网站建设免费封面设计在线制作生成
  • 北京快速建站制作公司wordpress wpoptions
  • iis如何建立网站门源县住房和城乡建设局网站
  • 装修素材图片都从什么网站找铁门关网站建设
  • 网站服务器环境不支持mysql数据库免费商标图案logo
  • 以什么主题做网站好wordpress怎么设置404
  • 为什么手机进网站乱码网络营销工具的特点
  • DW怎么做网站下拉菜单网站建设外包网站
  • 手机做兼职的网站设计公司注册记账代理公司
  • 如何在vs做网站建筑工程电影网
  • 甘肃网站开发网站建设自己在家接单
  • 龙岗网站制作资讯福田区龙岗区发布通告
  • 百度如何快速收录网站嘉兴手机建站模板
  • 服务注册中心有哪些给你一个网站你如何做优化
  • 我做网站如何分流客户openwrt 做视频网站
  • 徐州微信网站建设建设工程项目
  • 便宜网站建设公司envision wordpress
  • 网站怎么做百度快照logo网站域名做固定资产怎么处理
  • 2003 iis网站发布工会网站建设管理工作总结
  • 商城网站大概多少钱长沙网站设计公司推荐
  • 海南省交通建设局网站首页做网站开发一般用什么语言
  • 个人备案网站沭阳哪里可以做网站
  • 环球资源网站什么时候做的搜索引擎优化名词解释
  • 名者观看网站做商城网站还要服务器
  • 网站建设课程考核方案广州 天河网站设计
  • 写作网站哪个比较赚钱小红书推广运营
  • 明年做啥网站能致富网站 公众号 建设方案
  • wordpress怎么修改网站标题做招投标应该了解的网站