在Linux系统中,使用poll
函数来进行轮询。IO多路复用Epoll、Poll、Select介绍可参考前面的文章:C++中的IO多路复用(select、poll、epoll)总结_c++ epoll select poll是什么-CSDN博客 poll函数原型如下:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
poll
函数接受一个struct pollfd
数组,该数组包含多个文件描述符和相应的事件类型。poll
函数会阻塞,直到有一个或多个文件描述符上的事件发生。一旦发生事件,poll
函数会返回,同时将对应的文件描述符和事件类型存储在struct pollfd
结构体的revents
字段中。
/* Data structure describing a polling request. */
struct pollfd
{
int fd; /* File descriptor to poll. */
short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */
};
POLL
定义了一系列的事件类型,例如:
POLLIN
:表示有数据可读。POLLPRI
:表示有紧急数据可读。POLLOUT
:表示可以写入。POLLERR
:表示发生错误。POLLHUP
:表示关闭连接。POLLNVAL
:表示无效的轮询请求。
可以使用poll
函数进行轮询,在事件发生之后,通过检查revents
字段来确定具体的事件类型,并在相应的条件下进行处理。示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/poll.h>
int main() {
int fd1, fd2;
struct pollfd fds[2];
// 打开文件描述符,此处仅示意
fd1 = open("file1.txt", O_RDONLY);
fd2 = open("file2.txt", O_WRONLY);
// 初始化pollfd结构体数组
fds[0].fd = fd1;
fds[0].events = POLLIN; // 监听可读事件
fds[1].fd = fd2;
fds[1].events = POLLOUT; // 监听可写事件
// 轮询事件
int numEvents = poll(fds, 2, 5000); // 监听2个文件描述符,超时时间为5秒
if (numEvents > 0) {
// 遍历检查每个文件描述符上的事件
for (int i = 0; i < 2; i++) {
if (fds[i].revents & POLLIN) {
printf("数据可读\n");
// 在此处理可读事件
// 例如从文件中读取数据
}
if (fds[i].revents & POLLOUT) {
printf("可写数据\n");
// 在此处理可写事件
// 例如向文件中写入数据
}
}
} else if (numEvents == -1) {
perror("poll");
exit(EXIT_FAILURE);
} else {
printf("超时\n");
// 在此处理超时事件
}
// 关闭文件描述符,此处仅示意
close(fd1);
close(fd2);
return 0;
}
那么,我们为什么可以使用位运算符来存储标志位呢?首先我们可以查看POLLIN等事件在源代码中的值:
#ifndef _SYS_POLL_H
# error "Never use <bits/poll.h> directly; include <sys/poll.h> instead."
#endif
/* Event types that can be polled for. These bits may be set in `events'
to indicate the interesting event types; they will appear in `revents'
to indicate the status of the file descriptor. */
#define POLLIN 0x001 /* There is data to read. */
#define POLLPRI 0x002 /* There is urgent data to read. */
#define POLLOUT 0x004 /* Writing now will not block. */
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
/* These values are defined in XPG4.2. */
# define POLLRDNORM 0x040 /* Normal data may be read. */
# define POLLRDBAND 0x080 /* Priority data may be read. */
# define POLLWRNORM 0x100 /* Writing now will not block. */
# define POLLWRBAND 0x200 /* Priority data may be written. */
#endif
#ifdef __USE_GNU
/* These are extensions for Linux. */
# define POLLMSG 0x400
# define POLLREMOVE 0x1000
# define POLLRDHUP 0x2000
#endif
/* Event types always implicitly polled for. These bits need not be set in
`events', but they will appear in `revents' to indicate the status of
the file descriptor. */
#define POLLERR 0x008 /* Error condition. */
#define POLLHUP 0x010 /* Hung up. */
#define POLLNVAL 0x020 /* Invalid polling request. */
通过上面的代码我们可以看到,这些事件都被赋予了一定的值,我们将其转化为二进制再看看,可以发现每一个事件对应着二进制的每一位,即我们可以通过位运算来控制数据的每一位对应的事件:
具体位运算方法可以参考本文:利用位运算符设置标志位-CSDN博客