2.10 进程间通信简介
进程间通讯概念
简称:
GUI:图像用户 接口
IDE:集成开发环境
API:应用程序接口
Linux进程间通信的方式
还有一种:内存映射
2.11匿名管道概述
匿名管道
ls获取一个目录中文件的列表,“|”创建管道服务,wc统计文件数目。
管道的特点
管道两端对应文件描述符
从现实应用角度理解单工、双工、半双工:
单工-遥控器发送数据给电视
双工-打电话
半双工-同一时刻,数据只能往一个方向发送,比如对讲机
为什么可以使用管道进行进程间通信
fork()创建子进程,父子进程共享文件描述符fd,文件描述符表处于内核中,上图中5指向管道读端,6指向管道写端。
管道的数据结构
环形队列(循环队列)逻辑上,可覆盖被读走数据的内存写入数据
匿名管道的使用
2.12父子进程通过匿名管道通信
创建匿名管道
/*
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用来进程间通信。
参数:int pipefd[2] 这个数组是一个传出参数。
pipefd[0] 对应的是管道的读端
pipefd[1] 对应的是管道的写端
返回值:
成功 0
失败 -1
管道默认是阻塞的:如果管道中没有数据,read阻塞,如果管道满了,write阻塞
注意:匿名管道只能用于具有关系的进程之间的通信(父子进程,兄弟进程)
*/
// 子进程发送数据给父进程,父进程读取到数据输出
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// 重点:在fork之前创建管道
int pipefd[2];//传出参数
int ret = pipe(pipefd);
if(ret == -1) {
perror("pipe");
exit(0);
}
// 创建子进程
pid_t pid = fork();
if(pid > 0) {
// 父进程:可实现先读再写
printf("i am parent process, pid : %d\n", getpid());
// 关闭写端
//close(pipefd[1]);
// 从管道的读取端读取数据
char buf[1024] = {0};
while(1) {
int len = read(pipefd[0], buf, sizeof(buf));
printf("parent recv : %s, pid : %d\n", buf, getpid());
//向管道中写入数据
char * str = "hello,i am parent";
write(pipefd[1], str, strlen(str));
sleep(1);
}
} else if(pid == 0){
// 子进程:可实现先写再读
printf("i am child process, pid : %d\n", getpid());
// 关闭读端
//close(pipefd[0]);
char buf[1024] = {0};
while(1) {//while循环实现不断的发送数据
// 向管道中写入数据
char * str = "hello,i am child";
write(pipefd[1], str, strlen(str));
sleep(1);
//父子进程交替接收数据
int len = read(pipefd[0], buf, sizeof(buf));
printf("child recv : %s, pid : %d\n", buf, getpid());
bzero(buf, 1024);
}
}
return 0;
}
查看管道缓冲大小函数
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int pipefd[2];//传出参数
int ret = pipe(pipefd);
// 获取管道的大小:4KB 4096 可修改
//第二个参数为宏值,表示获取管道的大小
long size = fpathconf(pipefd[0], _PC_PIPE_BUF);
printf("pipe size : %ld\n", size);
return 0;
}