进程间通信
我们知道,进程之间是相互独立的,每个进程拥有自己虚拟地址空间,并且虚拟地址空间根据页表的映射,映射到属于自己的物理内存上。并且各个进程之间互相不影响,执行自己的代码。这样说来进程之间难道没有可能交流联系?显然是不可能的。
一般来说只要让我们互不相干的进程看到同一块公共资源,那么它们就可以在这片公共资源上面交流联系。与我们人一样,每个人都是一个独立的个体,但是到了一个公共场所,人与人之间就会不由的交流联系。
进程间通信的目的
进程之间的通信能够让进程之间进行数据的交换,并且这些进程共用一块公共资源,共同享有这些资源,进程之间进行信息的通知,如fork之后,子进程若退出则需要向父进程发送退出信息,让父进程来维护子进程的退出信息。同时,进程间如果能够通信交流,那么可以达到对进程的控制。
进程间通信的分类
进程间通信又分为管道通信、System V进程间通信、POSIX进程间通信。
而管道通信又分为匿名管道与命名管道通信。
System V进程间通信有:消息队列、共享内存、信号量,其中共享内存通信是速度最快的进程间通信方式。
POSIX进程间通信方式有:消息队列、共享内存、信号量、互斥量、条件变量、读写锁。
管道
说起管道通信,不由的就会想到在Linux平台下一个指令|
这便是一个管道通信的方式。而管道是Unix中最古老的进程间通信方式,管道如同水管,一边进入一边流出。同理进程也是一样,数据从管道入口输入,再从出口输出。
匿名管道
我们的匿名管道是可以在代码中利用函数pipe(int fd[2])
来创建的,如果管道创建成功返回0,失败返回错误码。
我们利用这个函数来实现一下我们的匿名管道通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pipefd[2];
if(pipe(pipefd) != 0)
{
printf("pipe error!\n");
return -1;
}
pid_t pid = fork();
if(pid < 0)
{
printf("fork error!\n");
return -1;
}
else if(pid == 0)
{
close(pipefd[0]);
write(pipefd[1],"hello",5);
close(pipefd[1]);
exit(1);
}
else
{
char buf[64];
close(pipefd[1]);
read(pipefd[0],buf,5);
printf("%s\n",buf);
}
return 0;
}
这里利用fork产生一个子进程, 然后让子进程在之前创建的管道内进行写入内容,写入一个hello,然后父进程去读这个hello到buf里面。这里注意,由于管道是单向的,所以子进程在写入内容之前,需将管道的读入,也就是fd[0]关闭,在写完之后再将fd[1]关闭,防止外来因素影响,而父进程同理,在读之前将fd[1]关闭。
我们的管道在进行读写时,如果写满管道,write调用阻塞,那么这个时候管道将无法写入,直到有进程读走管道内数据。当没有数据可以读是,read调用阻塞,进程暂停,直到有数据写入。
当管道的所有写端对应的文件描述符被关闭的时候,那么read将返回0,如果管道的所有读端对应的文件描述符被关闭的时候,则write操作会产生SIGPIPE信号,导致write进程退出。
匿名管道特点
匿名管道只能用于具有血缘关系的进程之间进行通信,一般来说由一个进程先产生一个管道,接着调用fork生成子进程,父子进程共用管道,达到其通信的目的。而进程退出,匿名管道随之释放,也就是说匿名管道的生命周期随着进程。管道是单向的,数据只能从一个方向流往另一个方向,如果要双向通信,那么则需要再次创建新管道。我们前面说过,两个进程只有看到一片公共资源那么它们才能通信,此时的匿名管道便是这个公共资源,又叫做临界资源。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!