1.进程通信的目的
(1) 数据传输: 一个进程需要将它的数据传输给另一个进程
(2) 资源共享: 多个进程之间共享同样的资源
(3) 通知事件: 一个进程需要向另一个或一组进程发送消息, 通知它们发生了什么事情
2.管道
管道是一种进程之间通信的一种方式, 我们把从一个进程连接到另一个进程的数据流叫做管道
3.匿名管道
(1) 匿名管道的创建
int pipe(int fd[2]);
fd是一个文件描述符数组, fd[0] 代表读端, fd[1] 代表写端
返回值:成功过时返回0, 失败时返回错误代码
4.代码演示
//clientPipe.c
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
int wfd = open("mypipe", O_WRONLY);
if(wfd == -1)//dakashibai
{
perror("open");
exit(1);
}
char buf[1024];
buf[0] = 0;
ssize_t s;
while(1)
{
printf("Please Enter#");
fflush(stdout);
s = read(0, buf, sizeof(buf));
if(s > 0)//成功读取
{
buf[s] = 0;
write(wfd, buf, s);
}
else if(s <= 0)//读取失败
{
perror("read");
exit(1);
}
}
}
//serverPipe.c
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/types.h>
int main()
{
int fifo = mkfifo("mypipe", 0644);
if(fifo == -1)//管道创建失败
{
perror("mkfifo");
exit(1);
}
//打开管道
int rfd = open("mypipe", O_RDONLY);
if(rfd == -1)//打开失败
{
perror("open");
exit(1);
}
//读管道数据
char buf[1024];
ssize_t s;
while(1)
{
buf[0] = 0;
printf("Please wait ... \n");
s = read(rfd, buf, sizeof(buf) -1);
if(s > 0)//读到数据
{
buf[s] = 0;
printf("client say# %s", buf);
}
else if(s == 0)//读完
{
printf("client quit, exit now\n");
exit(0);
}
else//读取失败
{
perror("read");
exit(1);
}
}
close(rfd);
return 0;
}
5.站在文件描述符角度理解
父进程先创建管道, 创建完管道,同时父进程打打开对应的读端和写端,接着父进程创建子进程, 由于子进程会继承父进程的特性, 因此子进程也会打开和父进程一样的读端和写端, 此时父子进程就看到了一份公共资源, 紧接着父进程将读端关闭, 子进程将写端关闭, 于是便可以父进程进行对数据的写,子进程只管从管道中读数据即可,于此父子进程合作完成读写工作.
6.管道读写规则
(1) 当管道读端关闭, 写端还在继续写的时候此时操作系统会给写端发送一个 SIGPIPE 的信号,从而使得写端退出
(2) 如果写端对应的描述符关闭, 读端则会正常退出.
(3) 管道具有上限,当写到 PIPE_BUF 时, Linux 将不再保证其写入的原子性.
(4) 注意匿名管道对应的两个进程之间一定是由血缘关系的
7. 管道特点
(1) 管道具有单向性
(2) 有血缘关系的进程之间才能进行通信(匿名管道)
(3) 管道必须满足同步互斥关系(管道没有数据时,读端进程将会不读,阻塞等待, 当管道已经满的时候就不能对管道进行写了)
(4) 管道的生命周期随进程
(5) 管道提供字节流服务(从管道中一次读多少由操作系统决定, 即一次读写多少不确定)
8. 相关的几个概念
(1) 数据不一致: 一个进程的读写影响到另外一个进程的读写
(2) 临界资源: 两个进程看到的一份公共资源,并且一次只允许一个进程使用
(3) 临界区: 进程访问临界资源的那段代码就叫做临界资源
(4) 互斥: 各进程有时需要共享资源, 而且有些资源需要互斥访问, 因此进程之间竞争使用这些资源, 进程之间的这种关系叫做互斥
(5) 进程访问资源的原子性: 进程在操作某些资源时要不做完, 要不不做, 中间不会收到如何其他进程的干扰.
(6) 同步: 进程之间以一种比较安全的顺序访问资源, 这种安全机制就叫做同步
(7) 管道自带同步互斥机制, 当管道中没有数据时父进程会等待子进程的退出