进程间通信
- 通信的本质:互相传递数据
- 进程间不能直接相互传递数据,因为进程具有独立性,所有的数据操作都会发生写时拷贝
- 进程间通信一定通过中间媒介(OS提供的内存空间)的方式来进行通信的
- 进程间通信的本质:让不同的进程能看到同一份系统资源(系统通过某种方式(方式是有差别的,决定了通信策略是有差异的)提供的系统内存)
进程间通信介绍
进程间通信目的
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变
进程间通信发展
- 管道
- System V进程间通信
- POSIX进程间通信
进程间通信分类
管道
- 匿名管道pipe
- 命名管道
System V IPC
- System V 消息队列
- System V 共享内存
- System V 信号量
POSIX IPC
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
管道
从一个进程连接到另一个进程的一个数据流称为一个“管道”
注:
- 管道只能进行单向数据通信
- 实现双向数据通信必须建立多个管道(由OS本身决定的)
- 并不是所有文件都能充当管道,管道是一种文件
补充:
-
管道是半双工通信
-
管道的本质是内核中的缓冲区
-
管道自带同步(没有数据读阻塞,缓冲区写满写阻塞)与互斥
-
多个进程只要能够访问同一管道就可以实现通信,不限于读写个数
-
管道的生命周期随进程,管道文件只是标识,删除后依然可以通信
匿名管道
- 匿名管道供具有血缘关系的进程,进行进程间通信(常见于父子进程)
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
用fork来共享管道原理
注:
- fork创建子进程之后,子进程会继承父进程的大部分数据(包括父进程中的fd_array[]),此外父子进程的文件描述符指向同一个文件的r、w。
- 匿名管道(保证不同进程看到同一份资源),同一分资源指的是系统中fork之后父子进程所指向同一份文件(struct file)下的’系统级"文件缓冲区
- 父子进程关闭不需要的文件操作符,从而达到构建单向通信的管道的目的
- 父进程必须都要打开文件的读写权限,不打开读写,子进程拿到的文件打开方式必定和父进程一样,将无法通信
- 父子进程打开文件的读写权限之后,必须要关闭相应的其中一个权限,原因是防止误操作
- int pipe(int pipefd[2]);中的参数为输出型参数,拿到打开的管道文件描述符是2个fd,分别为read,write
站在文件描述符角度-深度理解管道
站在内核角度-管道本质
代码实列:
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int pipe_fd[2]={
0};
if(pipe(pipe_fd)<0)
{
perror("pipe");
return 1;
}
printf("%d,%d\n",pipe_fd[0],pipe_fd[1]);
pid_t id=fork()