欢迎关注本公众号,专注面试题拆解
分享一套视频课程:《C++实现百万并发服务器》 面试需要项目的可以找我获取,免费分享。 欢迎V:fb964919126
面试题:poll中 events 和 revents分开的原因是什么?
在系统编程中,I/O 多路复用是一个永恒的话题。从最早的 select 到现代的 epoll,每一代机制都在试图解决同样的问题:如何高效地监控多个文件描述符的状态。在这个演进过程中,poll 机制虽然不是最新的技术,但其中 events 和 revents 分离的设计思想却值得我们深入研究。
01
基本设计
struct pollfd {
int fd; // 文件描述符
short events; // 要监视的事件(输入)
short revents; // 实际发生的事件(输出)
};
这种设计体现了关注点分离的原则。events 作为输入参数,由用户设置,表明用户对哪些事件感兴趣;revents 作为输出参数,由内核设置,表明实际发生了哪些事件。这种分离使得接口更加清晰,职责划分更加明确。
02
主要原因
2.1、 职责分离
void example_separation() {
struct pollfd fds[2];
// 1. events 由用户设置,表示关注什么事件
fds[0].events = POLLIN; // 关注读事件
fds[1].events = POLLOUT; // 关注写事件
// 2. revents 由内核设置,表示实际发生了什么事件
poll(fds, 2, -1);
// 现在 fds[0].revents 和 fds[1].revents 包含实际发生的事件
}
这种分离设计有几个重要优点:
明确的输入输出:用户清楚地知道哪些是自己需要设置的,哪些是系统会返回的
安全性:防止用户错误地修改返回值
接口清晰:避免了参数的二义性
便于调试:可以清楚地看到用户请求和系统响应的差异
2.2、 重用性
void example_reuse() {
struct pollfd fds[1];
// 1. 只需要设置一次 events
fds[0].events = POLLIN | POLLOUT;
// 2. 可以重复使用
while(1) {
// 每次调用前清零 revents
fds[0].revents = 0;
poll(fds, 1, -1);
// 处理事件
// events 无需重新设置
}
}
重用性的优势:
减少重复设置:events 只需要设置一次,避免了重复的初始化操作
提高性能:减少了不必要的内存写操作
代码简洁:避免了重复的初始化代码
降低错误风险:减少了重复设置可能带来的错误
2.3、 错误处理
void example_error() {
struct pollfd fds[1];
// 1. events 只设置关注的事件
fds[0].events = POLLIN;
poll(fds, 1, -1);
// 2. revents 可能包含错误标志,即使 events 中未设置
if (fds[0].revents & POLLERR) {
// 处理错误
}
if (fds[0].revents & POLLHUP) {
// 处理挂断
}
if (fds[0].revents & POLLNVAL) {
// 处理无效请求
}
}
错误处理的优势:
即使用户没有请求错误通知,也能收到错误信息,系统可以在 revents 中返回各种错误状态,错误标志不会与用户设置的 events 混淆。
03
与select的对比
void compare_with_select() {
// select 方式
fd_set readfds;
while(1) {
// 1. 每次都要重新设置
FD_ZERO(&readfds);
FD_SET(fd1, &readfds);
FD_SET(fd2, &readfds);
select(maxfd + 1, &readfds, NULL, NULL, NULL);
// readfds 被修改,下次循环需要重新设置
}
// poll 方式
struct pollfd fds[2];
// 只需要设置一次
fds[0].events = POLLIN;
fds[1].events = POLLIN;
while(1) {
fds[0].revents = 0;
fds[1].revents = 0;
poll(fds, 2, -1);
// events 保持不变,可以继续使用
}
}
与 select 相比的优势:
更高效的重用:不需要每次重新设置所有文件描述符
更清晰的状态管理:输入和输出状态分离
更好的扩展性:没有文件描述符数量的固定限制
更低的系统开销:减少了数据复制和重置操作
这种设计不仅提高了代码的可维护性和可读性,还带来了性能上的优势。在实际应用中,这种设计使得 poll 比 select 更受欢迎,特别是在需要监控大量文件描述符的场景中。
04
会议总结
poll 中 events 和 revents 的分离机制,虽然是一个简单设计但是这种设计充分体现了"单一职责原则"和"关注点分离"的设计思想。
end
CppPlayer
关注,回复【电子书】珍藏CPP电子书资料赠送
精彩文章合集
专题推荐