博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第十五章:进程间通信
阅读量:4328 次
发布时间:2019-06-06

本文共 3076 字,大约阅读时间需要 10 分钟。

15.1:引言

 第8章说明了进程控制原语并且观察了如何调用多个进程。但是这些进程之间交换信息的方法只能经由fork或exec传送打开文件,或者通过文件系统。本章将说明进程之间相互通信的其他技术--IPC(InterProcess Communication)。

过去,Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Unix系统实现中进行移植。随着Posix和open group(以前是X/Open)标准化的推进和影响的扩大,情况虽然已得到改善,但差别仍然存在。下图列出了本书讨论的四种实现所支持的不同形式的IPC。

我们将IPC的讨论分为3章。本章讨论经典的IPC:管道、FIFO、消息队列、信号量以及共享存储器。下一章将观察使用套接字的网络IPC。第17章将考查IPC的某些高级特征。

15.2:管道

管道是由调用pipe函数而创建的:

#include 
int pipe(int filedes[2]);// 返回值:若成功则返回0,若出错则返回-1

经由参数filedes返回的两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。

调用fork之后做什么取决于我们想要有的数据流的方向。对于从父进程到子进程的管道,父进程关闭管道的读端(fd[0]),子进程则关闭写端(fd[1])。下图显示了在此之后描述符的安排。

为了构造从子进程到父进程的管道,父进程关闭fd[1],子进程关闭fd[0]。

当管道的一端被关闭后,下列两条规则起作用:

(1)当读一个写端已被关闭的管道时,在所有数据都被读取之后,read返回0,以指示达到了文件结束处。

(2)如果写一个读端已被关闭的管道时,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write返回-1,errno设置为EPIPE。

示例:经由管道父进程向子进程传送数据

#include 
#include
#include
#define MAXLINE 256int main(void){ int n; int fd[2]; pid_t pid; char line[MAXLINE]; if (pipe(fd) < 0) { perror("pipe error"); } if ((pid = fork()) > 0) { // parent close(fd[0]); write(fd[1], "Hello world!", 12); } else if (pid == 0) { // child close(fd[1]); n = read(fd[0], line, MAXLINE); write(1, line, n); } else { // error perror("fork error"); } return 0;}

在上面的例子中,直接对管道描述符调用read和write。更好的方法是将管道描述符复制为标准输入和标准输出。在此之后通常子进程执行另一个程序,改程序或者从标准输入读数据,或者将数据写至其标准输出。

试编写一个程序,其功能时每次一页显示已产生的输出。

示例:将文件复制到分页程序

#include 
#include
#include
#include
#include
#include
#define DEF_PAGER "/bin/more" // default pager program#define MAXLINE 256int main(int argc, char **argv){ int n; int fd[2]; pid_t pid; char *pager, *argv0; char line[MAXLINE + 1]; memset(line, 0, MAXLINE + 1); FILE *fp; if (argc != 2) { printf("Usage: a.out
\n"); return -1; } if ((fp = fopen(argv[1], "r")) == NULL) { perror("can't open file"); return -1; } if (pipe(fd) < 0) { perror("pipe error"); return -1; } if ((pid = fork()) > 0) { // parent close(fd[0]); while (fgets(line, MAXLINE, fp) != NULL) { n = strlen(line); if (write(fd[1], line, n) != n) { perror("write error to pipe"); } } if (ferror(fp)) { perror("fgets error"); } close(fd[1]); if (waitpid(pid, NULL, 0) < 0) { perror("waitpid error"); } return 0; } else if (pid == 0) { // child close(fd[1]); if (fd[0] != STDIN_FILENO) { if (dup2(fd[0], STDIN_FILENO) != 0) { perror("dup2 error to stdin"); } close(fd[0]); } pager = getenv("PAGER"); if ((pager = getenv("PAGER")) == NULL) { pager = DEF_PAGER; } if ((argv0 = strrchr(pager, '/')) != NULL) { argv0++; } else { argv0 = pager; } if (execl(pager, argv0, (char*)0) < 0) { perror("execl error for pager"); } } else { // error perror("fork error"); return -1; } return 0;}

15.3:popen和pclose函数

常见的操作是创建一个管道连接到另一个进程,然后读取其输出或者向其输入端发送数据,为此,标准I/O库提供了两个函数popen和pclose。这两个函数实现的操作是:创建一个管道,调用fork产生一个子进程,关闭管道的不使用端,执行一个shell以运行命令,然后等待命令终止。

 

转载于:https://www.cnblogs.com/lit10050528/p/4929553.html

你可能感兴趣的文章
RTMP
查看>>
求一个数的整数次方
查看>>
点云PCL中小细节
查看>>
铁路信号基础
查看>>
RobotFramework自动化2-自定义关键字
查看>>
[置顶] 【cocos2d-x入门实战】微信飞机大战之三:飞机要起飞了
查看>>
BABOK - 需求分析(Requirements Analysis)概述
查看>>
第43条:掌握GCD及操作队列的使用时机
查看>>
Windows autoKeras的下载与安装连接
查看>>
CMU Bomblab 答案
查看>>
微信支付之异步通知签名错误
查看>>
2016 - 1 -17 GCD学习总结
查看>>
linux安装php-redis扩展(转)
查看>>
Vue集成微信开发趟坑:公众号以及JSSDK相关
查看>>
技术分析淘宝的超卖宝贝
查看>>
i++和++1
查看>>
react.js
查看>>
P1313 计算系数
查看>>
NSString的长度比较方法(一)
查看>>
Azure云服务托管恶意软件
查看>>