我们往往需要多个进程协同,共同完成一些事情。
进程间通信的本质:要让不同的进程看到同一份资源,这份资源一般是由操作系统提供的。操作系统提供的资源不同,就决定了有不同的通信方式。
基于文件的方式,让不同进程看到同一份资源的通信方式,叫做管道,管道通信只能为单向通信。如果今天我们让父进程以读和写两种方式打开同一个文件,操作系统是会为我们创建两个struct file结构体的,只不过这两个struct file结构体的缓冲区是同一个。如果我们让这个父进程创建一个子进程,子进程的PCB和文件描述符表和父进程一模一样,所以此时子进程也是以读和写两种方式打开了父进程打开的这个文件。这样操作就让父子进程看到了同一份资源。也就是说,struct file对象是允许多个进程通过指针指向它的。
前面也说过,管道通信为单向通信,所以如果想让父进程写子进程读,就关闭父进程的读端关闭子进程的写端,反之亦然。
pipe可以帮我们创建一个不需要向磁盘刷新且磁盘中并不存在的文件,也就是管道。这是一个内存级的文件,是匿名文件或叫匿名管道。匿名管道只能让具有血缘关系的进程进行进程通信,常用于父子进程之间进行进程通信。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
void writer(int wfd)
{
char buffer[128];
int count = 0;
while (1)
{
snprintf(buffer, sizeof(buffer), "I am your child!, pid:%d, count:%d\n", getpid(), count++);
write(wfd, buffer, strlen(buffer));
sleep(1);
}
}
void reader(int rfd)
{
char buffer[128];
while (1)
{
read(rfd, buffer, sizeof(buffer));
printf("father get message:%s", buffer);
}
}
int main()
{
int pipefd[2];
int n = pipe(pipefd);
int fd = fork();
if(fd == 0)
{
//子进程充当写端,从而关闭读端
close(pipefd[0]);
writer(pipefd[1]);
exit(0);
}
//父进程充当读端,从而关闭写端
close(pipefd[1]);
reader(pipefd[0]);
wait(NULL);
return 0;
}
父进程不断读到从子进程发来的消息: