8.10 pipe通信
8.10.1 pipe的使用
管道是为进程提供的一种通信方式,一般用来做进程同步和进程间通信。Linux中提供的有名管道的建立函数为:int pipe(int pipe[2]);
#include<unistd.h>
int pipe(int filedes[2]);
// 函数说明: pipe()会建立管道,并将文件描述词由参数filedes数组返回;filedes[0]为管道里的读取端;filedes[1]则为管道的写入端。
对于管道的读写都是直接通过读写文件描述符filedes完成。且默认阻塞,即管道数据满的时候写操作被阻塞,数据空的时候读操作被阻塞。
示例代码:
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;
int main()
{
int pipefd[2];
pipe(pipefd); //包含于<unistd.h>,定义了一个管道,同时也打开了参数的文件描述符
pid_t pid = fork();
if (pid < 0)
{
cerr << "fork error!" << endl;
return -1;
}
else if (pid > 0)
{
cout << "I'm the parent process! Now write to the pipe!" << endl;
close(pipefd[0]);//关闭管道的读取端
char sendMsg[100] = "heiheihei";//这是要传递的信息
write(pipefd[1], sendMsg, 100);//将信息写入管道
close(pipefd[1]);//写完之后关闭写入端
}
else if (pid == 0)
{
cout << "I'm the child process!";
close(pipefd[1]);//过程和写入是类似的
char receiveMsg[100];
read(pipefd[0], receiveMsg, 100);//如果管道为空,这个函数默认被阻塞
close(pipefd[0]);
cout << "Now I've recerive the message:" << receiveMsg << endl;
}
waitpid(pid, NULL ,0); //包含于<sys/wait.h>,等待子进程结束并清理其资源
return 0;
}
8.10.2 pipe与epoll
epoll为何需要用pipe?
epoll可以监听多个文件描述符的事件,但是当没有文件描述符上发生事件时,epoll也会被阻塞,这就需要一种机制来唤醒epoll,这就是pipe的用途。pipe的读句柄的可读事件会被加入到epoll中,当pipe中有数据写入时,epoll就会触发,从而唤醒epoll,让它继续监听文件描述符的事件。
那为什么不直接用pipe呐,不采用epoll?
用pipe可以实现进程间的通信,但是它只能监听一个文件描述符的事件,如果要监听更多的文件描述符的事件,就需要用epoll,因为它可以同时监听多个文件描述符的事件,因此epoll更有效率。
epoll也可以不用pipe,那么epoll还可以用其他的机制来唤醒epoll么?
epoll也可以用其他机制来唤醒epoll,epoll 的唤醒是通过系统调用epoll_ctl来实现的,当一个新的文件描述符就绪时,epoll_ctl会唤醒epoll;
epoll 可以同时处理读和写的事件,通过调用 epoll_ctl 函数,向 epoll 内核事件表注册读写事件,当描述符上有读或写事件发生时,epoll 会将事件加入到内核事件表中,epoll_wait 会返回事件列表,这样就可以处理读写事件了。