目录
前言
哈喽,小伙伴们大家好。我们都知道在完成一个任务时,往往是多个进程一起协调工作的,那么在工作的过程中,进程间必然需要产生交流,那么它们之间是如何交流的呢?本篇文章将给大家答疑解惑,详细讲解进程间通信。事不宜迟,快拿起小本本,和我一起开始吧。
一、进程通信介绍
1、进程通信的目的
- 数据传输:一个进程需要将它的数据发送给另一个进程。
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
- 进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
2、进程通信的实现
进程间通信的实现基础就是让不同的进程看到同一份资源(内存,文件内核缓冲等)。根据资源提供者的不同,就有了不同的进程通信的方式。
进程通信的特点:
- 进程运行时是具有独立性的。(数据)
- 进程间通信,一般一定要借助第三方(OS)资源。
- 通信的本质就是数据拷贝,进程A把数据给OS,OS再把数据拷贝给进程B,就实现了进程A和B的通信。由此我们可以得知,OS一定要能提供一段内存区域,给双方进程看到。
进程间通信的分类:
- 管道
- System V进程间通信
- POSIX进程间通信
二、管道
管道概念:管道是Unix中最古老的通信方式,我们把一个进程连接到另一个进程的数据流称为管道。管道分为匿名管道和命名管道。
(一)匿名管道
1、基本概念
管道是使用文件方式来进行数据共享,这个文件是由操作系统提供的。进程A向文件中写入数据,进程B再去文件中拿,就实现了进程通信。管道用的虽然是文件的方案,但是os一定不会把数据刷新到磁盘,因为有IO参与会降低效率,也没有必要。所谓匿名管道就是没有文件名的文件。
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回-1
fd是一个输出型参数,里面保存的是打开文件的文件描述符。
在调用pipe函数后,对os中的文件分别以读和写的方式打开,管道建立。fd[0]为以读方式打开文件的文件描述符,fd[1]为以写方式打开文件的文见描述符。
2、管道原理
2.1、代码实例
我们用fork创建一个子进程,然后通过管道实现父子进程间的通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int fd[2] = {0};
if(pipe(fd)<0){
perror("pipe!");
return 1;
}
pid_t id=fork();
if(id==0)
{
//child
close(fd[0]);
int count=10;
const char* str="i am child";
while(count)
{
write(fd[1],str,strlen(str));
count--;
sleep(1);
}
close(fd[1]);
exit(0);
}
else
{
//father
char buff[64];
while(1)
{
ssize_t s=read(fd[0],buff,sizeof(buff));//s为实际读到的数据大小,如果为0则证明读完了
buff[s]='\0';
if(s>0)
{
printf("child send to father:%s\n",buff);
}
else if(s==0)
{
printf("read file end\n");
break;
}
else
{
printf("read erroe\n");
break;
}
}
waitpid(id,NULL,0);
}
return 0;
}
可以看到每隔一秒,父进程就会从管道中拿一次子进程的数据打印到显示器上。