-
进程间通信的目的
数据传输:一个进程将他的数据发送给另外一个进程
资源共享:多个进程之间共享同样的资源
通知事件:一个进程需要向另一个或者另一组进程发送信息,通知他们发生了某件事
进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道他的状态改变。 -
进程间通信
进程间为什么需要沟通交流?
在实际工作中往往会出现一个系统中好几个进程协同工作,那么这些进程就需要交流沟通才能完成协助。
因为进程的独立性,因此进程间沟通就变得困难,复杂。因此产生了进程的通信方式,来解决进程如何通信的问题。 -
进程间通信的发展
管道:管道是UNIX中最古老的进程间通信方式。
我们把从一个进程连接到另一个进程的数据流称为管道。
管道有一个很重要的特点:单向通信(它本质上是一块内核的缓冲区
操作系统为管道提供的方法是:文件操作 -
管道的读写规则
1.当没有数据可读时:
O_NONBLOCK disable:read 调用阻塞,进程暂停执行,直到有数据来为止。(就像水管里没有水,只有等待水来了才能接水)
O_NONBLOCK enable:read 调用返回-1,errno值为EAGAIN.
2.当管道满了时:
O_NONBLOCK disable:write调用阻塞,直到有进程读走数据
(就像水管里水是满的,只有你接走了水管里的水,水管才能进入新的水)
O_NONBLOCK enable:调用返回-1,errno值为ENGAIN. -
匿名管道的特点
1.只能用于有共同祖先或者亲缘关系的进程,通常一个管道由一个进程创建,然后该进程调用fork函数,之后父子进程就可以使用该管道。
2.管道提供流式服务
3.管道的生命周期跟随进程终止
4.管道是半双工的,数据只能向一个方向流动,需要数据互通时需建立两个管道。
5.管道是面向字节流传输数据的:
面向字节流:收发数据比较灵活,数据无规则发送,数据无边界。
面向数据报:数据只能整条接收
6.管道自带同步与互斥
临界资源:大家都能访问的公共资源
临界区:对临界资源进行操作的代码
同步:访问的可控时序性
互斥:对临界资源的同一时间内唯一访问性(保护临界资源的安全)
-
管道的分类:匿名管道/命名管道
1.匿名管道:仅用于具有亲缘关系的进程通信
示例代码:
//这是一个匿名管道的实现,功能:父进程写入数据,子进程读取打印数据
//int pipe(int pipefd[2])
//pipefe:用于接收匿名管道创建成功后返回的两个描述符
//这是一个匿名管道的实现,功能:父进程写入数据,子进程读取打印数据
//int pipe(int pipefd[2])
//pipefe:用于接收匿名管道创建成功后返回的两个描述符
//pipefd[0]用于从管道读取数据
//pipefd[1]用于从管道写入数据
// 成功返回0, 失败返回-1
//匿名管道仅用于具有亲缘关系的进程通信
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
int fd[2];//管道需要在创建子进程之前创建好,才能复制
if(pipe(fd)<0){
perror("pipe error");
return -1;
}
int pid=-1;
pid=fork();//创建子进程
if(pid<0)return -1;//当pid小于0时,进程创建失败
else if(pid==0){//子进程内读取数据
//子进程读取数据
close(fd[1]);//因为是读取数据所以关闭fd【1】
char buff[1024]={0};
read(fd[0],buff,1024);//读取buff中存的字符串
printf("child: %s\n",buff);//打印字符串
close(fd[0]);//读取完毕关闭fd【0】
}else{//父进程内写入数据
close(fd[0]);//因为是写入数据,所以关闭fd[0]
write(fd[1],"hello",5);//写入hello,5个字符
close(fd[1]);//写入完毕,关闭fd【1】
}
return 0;
}