目录
进程间通信的目的
数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程间通信的必要性本质以及技术背景
进程间通信的必要性,单进程的,那么也就无法使用并发能力,更加无法实现多进程协同。传输数据,同步执行流,消息通知等,所以进程通信不是目的,而是手段。
进程间通信的技术背景
1.进程是具有独立性的。虚拟地址空间+页表保证进程运行的独立性(进程内核数据结构+进程的代码和数据)。
2.通信成本会比较高。
进程间通信的本质理解
1.进程间通信的前提,首先需要让不同的进程看到同一块"内存"(特定的结构组织的)
2.所以你所谓的进程看到同一块"内存",属于哪一个进程呢?不能隶属于任何一个进程,而应该更强调共享。
管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
管道又分为两种,匿名管道和命名管道。
管道的原理:
这个就叫做管道,分别以读写的方式打开一个文件,fork()创建子进程,双方关闭自己不需要的文件描述符,管道就是文件,两个进程通过文件的方式进行通信。
匿名管道
#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
其实从上面这张都就可以看出管道是怎们样的,接下来就用代码来实现一下。
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
// 为什么不定义全局buffer来进行通信呢?? 因为有写时拷贝的存在,无法更改通信!
int main()
{
// 1. 创建管道
int pipefd[2] = {0};
int n = pipe(pipefd);
assert(n == 0);
(void)n;
#ifdef DEBUG
cout << "pipefd[0]: " << pipefd[0] << endl; // 3
cout << "pipefd[1]: " << pipefd[1] << endl; // 4
#endif
// 2. 创建子进程
pid_t id = fork();
assert(id != -1);
if (id == 0)
{
// 子进程 - 读
// 3. 构建单向通信的信道,父进程写入,子进程读取
// 3.1 关闭子进程不需要的fd
close(pipefd[1]);
char buffer[1024 * 8];
while (true)
{
// sleep(20);
// 写入的一方,fd没有关闭,如果有数据,就读,没有数据就等
// 写入的一方,fd关闭, 读取的一方,read会返回0,表示读到了文件的结尾!
ssize_t s = read(pipefd[0], buffer, sizeof(buffer) - 1);
if (s > 0)
{
buffer[s] = '\0';