面试题答案
一键面试poll机制使用的数据结构
在Linux中,poll
机制使用pollfd
结构体来表示需要监控的文件描述符及其相关信息。该结构体定义在<poll.h>
头文件中,通常形式如下:
struct pollfd {
int fd; /* 文件描述符 */
short events; /* 等待的事件 */
short revents; /* 发生的事件 */
};
- fd:指定要监控的文件描述符。如果
fd
为负数,则events
字段会被忽略,并且revents
字段会被设置为0。 - events:是一个位掩码,用于指定应用程序感兴趣的事件类型。常见的事件类型有
POLLIN
(数据可读)、POLLOUT
(数据可写)、POLLPRI
(有紧急数据可读)等。 - revents:由内核在
poll
调用返回时设置,它也是一个位掩码,指示实际发生的事件。这些事件是events
中请求的事件的子集。
poll机制的工作原理
- 添加监控的文件描述符
应用程序通过填充
pollfd
结构体数组,并将该数组作为参数传递给poll
函数来添加需要监控的文件描述符。例如:
#include <poll.h>
#include <stdio.h>
#include <unistd.h>
#define MAX_FDS 10
int main() {
struct pollfd fds[MAX_FDS];
// 初始化fds数组,设置要监控的文件描述符和感兴趣的事件
for (int i = 0; i < MAX_FDS; i++) {
fds[i].fd = i; // 假设这里的文件描述符是0到9
fds[i].events = POLLIN; // 只关心可读事件
}
int num_fds = MAX_FDS;
int timeout = -1; // 无限期等待
int ret = poll(fds, num_fds, timeout);
if (ret > 0) {
// 有事件发生,检查每个文件描述符的revents
for (int i = 0; i < num_fds; i++) {
if (fds[i].revents & POLLIN) {
printf("File descriptor %d is readable\n", fds[i].fd);
}
}
} else if (ret == 0) {
printf("Timeout occurred\n");
} else {
perror("poll error");
}
return 0;
}
- 检测事件
poll
函数会阻塞调用线程,直到以下情况之一发生:- 数组中的任何一个文件描述符上发生了请求的事件。在这种情况下,
poll
函数返回大于0的值,该值表示发生事件的文件描述符的数量。应用程序可以遍历pollfd
数组,检查每个元素的revents
字段,以确定具体发生了哪些事件。 - 发生了信号中断。此时
poll
函数返回 -1,并且errno
被设置为EINTR
。 - 超时时间到(如果设置了非无限期的超时)。如果设置了超时时间(
timeout
参数大于0),并且在超时时间内没有任何事件发生,poll
函数将返回0。
- 数组中的任何一个文件描述符上发生了请求的事件。在这种情况下,
poll
函数通过系统调用进入内核,内核会为每个文件描述符维护一个等待队列。当文件描述符的状态发生变化(例如有数据可读、可写等)时,内核会唤醒等待队列上的进程或线程,从而使得poll
函数返回,应用程序可以处理相应的事件。