linux多进/线程编程(4)——进程间通信之pipe和fifo
2024-10-07 11:56:22
前言:
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
常用的进程间通信方式有:
① 管道 (使用最简单)
② 信号 (开销最小)
③ 共享映射区 (无血缘关系)
④ 本地套接字 (最稳定) https://zhuanlan.zhihu.com/p/336734605
本文主要讲解pipe管道的用法和代码示例。
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
1. 数据一旦被读走,便不在管道中存在,不可反复读取。
2. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
3. 只能在有公共祖先的进程间使用管道。
pipe
NAME
pipe, pipe2 - create pipe SYNOPSIS
#include <unistd.h> int pipe(int pipefd[2]); #define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h> int pipe2(int pipefd[2], int flags);
利用pipe实现ps aux | grep bash
int pipe_fd[2];
pipe(pipe_fd); pid_t pid = fork(); if (pid == 0) {
//son -----> 这里会产生僵尸进程
//管道的使用规范:关闭读端
close(pipe_fd[0]);
//1.先重定向
dup2(pipe_fd[1], STDOUT_FILENO);//标准输出重定向到管道写端
//2.execlp
execlp("ps", "ps", "aux", nullptr);
} else if (pid > 0) {
//parent
//管道的使用规范:关闭写端
close(pipe_fd[1]);
//1.先重定向
dup2(pipe_fd[0], STDIN_FILENO);//标准输入重定向到管道读端
//2.execlp -----> grep 会阻塞
execlp("grep", "grep", "--color=auto", "bash", nullptr);
//代码的问题:父进程认为还有写端存在,就有可能还有人给发数据,继续等待
//管道的使用规范
}
fifo 可以实现无血缘关系的进程间通信
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h> int main(int argc, char * argv[]) {
if (argc != 2) {
printf("./a.out fifonname\n");
return -1;
}
//当前目录有一个myfifo文件
//打开fifo文件
int fd = open(argv[1], O_WRONLY);
//写
char buf[256];
int num = 1;
while(1) {
memset(buf, 0x00, sizeof(buf));
//循环写
sprintf(buf, "xiaoming%04d", num++);
write(fd, buf, strlen(buf));
sleep(1);
} //关闭描述符
closde(fd); return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h> int main(int argc, char * argv[]) {
if (argc != 2) {
printf("./a.out fifonname\n");
return -1;
}
//当前目录有一个myfifo文件
//打开fifo文件
int fd = open(argv[1], O_RDONLY); char buf[256];
int ret = 0;
while(1) {
//循环读
ret = read(fd, buf, sizeof(buf));
if (ret > 0) {
printf("read:%s\n", buf);
}
} //关闭描述符
closde(fd); return 0;
}
最新文章
- Angular 2 - 5 分钟快速入门
- iOS 打包iPa
- pay-as-you-go
- sqlplus 初始化文件(每一次打开sqlplus不用重新设置 linesize 和 pagesize)
- php基础06:运算符
- noip2011提高组day1+day2解题报告
- Oracle数据库的导入与导出
- linux时间方面的设置
- Eclipse导入Android签名
- pip&;easy_install使用
- @PostConstruct 和 @PreConstruct
- 黄聪:C#获取网页HTML内容的三种方式
- 更新 Anaconda 库文件
- python杂记一
- 小程序基础知识点讲解-WXML + WXSS + JS,生命周期
- 大话设计模式C++ 备忘录模式
- VarIsOrdinal,VarIsFloat,VarIsNumeric判断数字
- nginx日志
- p132代码解析
- HDU1506(真心不错的DP)