文章目录
进程间通信
进程和进程之间的关系,即进程间通信IPC。
进程间通信的目的
Q:为什么要有进程间通信?进程间通信的目的?
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享相同的资源
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知进程发生事件
- 进程控制:有些进程希望完全控制另一个进程的执行,希望获得进程的状态
进程间通信如何做到
Q:进程间通信如何做到?
进程运行的时候具有独立性,在数据层面上。
进程间通信,一般需要通过第三方(OS)资源。
通信的本质就是“数据的拷贝”,让不同的进程看到同一份资源(内存,文件内核缓冲等)
进程A -> 进程A将数据“拷贝”给OS -> OS将数据“拷贝”给进程B
所以操作系统需要提供一段内存区域,并且这一块内存区域可以让两个进程都可以看到。
其中看到的同一份资源的不同种类(由操作系统中不同的模块提供)就是不同的通信方式。
通信的发展
- 管道
- System V进程间通信
- POSIX进程间通信
通信有标准(技术路径的发展方向,包括现存的技术)
进程间通信分类
管道
- 匿名管道pipe
- 命名管道
System V IPC
- System V 消息队列
- System V 共享内存
- System V 信号量
POSIX IPC
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
管道
^pipe
什么是管道
管道是Unix中最古来的进程间通信的形式,将从一个进程连接到另一个进程的数据流称为一个“管道”。
![[Pasted image 20220203220818.png]]
使用文件的方式,来进行数据共享就是管道通信。管道虽然用的是文件的方案,其实os不会把数据刷新到磁盘上。(如果刷新到磁盘上的话就涉及到IO了,就降低速度)
who
用于查看当前Linux的登录用户。
who | wc -l
统计行数
匿名管道
匿名管道,即没有文件名
管道只能进行单向通信,
匿名管道的使用
原型:
int pipe(int fd[2])
参数:
fd:文件描述符数组,其中fd[0]
是读端,fd[1]
是写端。
返回值:
成功返回0,失败返回错误代码
其中int fd[2]
是输出型参数。
-
父进程创建管道
![[Pasted image 20220203221905.png]] -
父进程fork创建子进程
![[Pasted image 20220203221952.png]]
本质是为了让父子进程看到同一份资源,通常是父子进程进行通信的方式。
下面需要确认谁读谁写,关闭对应的读写端。
- 父进程关闭
fd[0]
,子进程关闭fd[1]
![[Pasted image 20220203222346.png]]
一开始父进程读写端都打开是为了让子进程继承,而因为管道只能单向通信所以必须要关闭进程对应的读写端。
一般情况下
fd[0]
:保存读文件描述符
fd[1]
:保存写文件描述符
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
// 子进程写入,父进程读取
int main()
{
int fd[2] = {
0};
if (pipe(fd) < 0)
{
perror("pipe");
return 1;
}
pid_t id = fork();
// 子进程
if (id == 0)
{
// 关闭读端
close(fd[0]);
int count = 10;
const char* msg = "I am child process";
while (count --)
{
write(fd[1], msg, strlen(msg));
sleep(1);
}
close(fd[1]);
// 子进程退出
exit(0);
}
// 父进程
// 关闭写端
close(fd[1]);
char buff[64];
while (1)
{
// size_t是unsigned int
// ssize_t是int
ssize_t s = read(fd[0], buff, sizeof(buff));
// s是从管道中实际读到的字节个数
if (s > 0)
{
buff[s] = '\0';
printf("child process send to father process# %s\n", buff);
}
else if (s == 0)
{
printf("read file end\n");
}
else
{
perror("read");
}
}
waitpid(id, NULL, 0);