poll,epoll都是常见的多路复用阻塞函数,当然还有select,今天就来学习一下它们是怎么使用的吧。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <poll.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define MYMOUSE "/dev/hello" #define END "end" #define INFTIM -1 static char buf[128]; void *poll_thread(void) { int fd = -1; int ret = -1; struct pollfd pollfds[2] = {0}; //监听2路事件,也可以设置更多路 pollfds[0].fd = 0; //0既标准输入,就是键盘 pollfds[0].events = POLLIN; //设置监听输入事件 fd = open(MYMOUSE, O_RDONLY); //自定义的设备节点 pollfds[1].fd = fd; pollfds[1].events = POLLIN; //设置监听输入事件 for(;;) { ret = poll(pollfds, 2, INFTIM); //2表示fd的数量,INFTIM即-1,表示无限阻塞等待,设置大于0表示超时等待,比如3000表示如果3秒内没有事件则自动返回0 if(ret > 0) //大于0表示正常的产生事件 { if(pollfds[0].revents & POLLIN) //判断是否为键盘的输入事件 {
read(pollfds[0].fd, buf, sizeof(buf)); printf("read for pollfds[0].fd = %s\n", buf); if(strncmp(buf, END, strlen(END)) == 0) //如果输入end结束程序 { printf("thread exit.\n"); break; } } if(pollfds[1].revents & POLLIN) //判断是否为自定义fd的输入事件 {memset(buf, 0, sizeof(buf));
read(pollfds[1].fd, buf, sizeof(buf)); printf("read for pollfds[1].fd = %s\n", buf); } } else if(ret == 0) //poll的第三个参数大于0时才有意义,当前设置为-1表示无限等待,是不会返回0的 { perror("poll time out.\n"); break; } else (ret < 0) // 小于0表示出错 { perror("poll"); break; } } return NULL;}memset(buf, 0, sizeof(buf));
void *epoll_thread(void)
{
int my_fd = -1, epoll_fd = -1;
int ret = -1;
int i = 0;
struct epoll_event event[2], max_event[MAXEVENTS]; //evnet[2]为要监听的两路事件,max_event[MAXEVENTS]表示随时能处理的最大事件数量
epoll_fd = epoll_create(2); // 创建epoll的句柄
if(epoll_fd < 0)
{
perror("epoll_create");
return NULL;
}
event[0].data.fd = 0; //0既标准输入,就是键盘
event[0].events = EPOLLIN | EPOLLET;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event[0]); //通过EPOLL_CTL_ADD加入对键盘的监听
my_fd = open(MYFD, O_RDONLY); //自定义一个监听
event[1].data.fd = my_fd;
event[1].events = EPOLLIN | EPOLLET;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event[1]);
for(;;)
{
ret = epoll_wait(epoll_fd, max_event, MAXEVENTS, INFTIM); //阻塞等待事件发生
if(ret > 0)
{
for(i = 0; i < ret; i++)
{
if(max_event[i].data.fd == 0) //判断事件是否来自键盘
{
memset(buf, 0, sizeof(buf));
read(0, buf, sizeof(buf));
printf("read fd0 buf=%s, ret=%d\n", buf, ret);
if(strncmp(buf, END, strlen(END)) == 0)
{
printf("thread exit.\n");
return NULL;
}
}
if(max_event[i].data.fd == my_fd) //判断事件是否来自自定义的fd
{
memset(buf, 0, sizeof(buf));
read(my_fd, buf, sizeof(buf));
printf("read my_fd buf=%s, ret=%d\n", buf, ret);
}
}
}
else if(ret == 0) //epoll_wait最后一个参数为-1,表示无限等待,因此不会超时
{
perror("time out,\n");
}
else
{
perror("error,\n");
}
}
return NULL;
}
void *select_thread(void)
{
int my_fd = -1, ret = -1;
fd_set fd_set1;
FD_ZERO(&fd_set1); //对fd_set清零
FD_SET(0, &fd_set1); //设置对0的监听,0即标准输入,就是键盘
my_fd = open(MYFD, O_RDONLY); //打开一个自定义的句柄
FD_SET(my_fd, &fd_set1); //增添一个自定义的监听
while(1)
{
ret = select(my_fd+1, &fd_set1, NULL, NULL, NULL); //阻塞等待事件发生
if(ret > 0)
{
if (FD_ISSET(0, &fd_set1)) //判断事件是否来自键盘
{
memset(buf, 0, sizeof(buf));
read(0, buf, sizeof(buf));
printf("read fd0 buf=%s\n", buf);
if(strncmp(buf, END, strlen(END)) == 0)
{
printf("thread exit.\n");
break;
}
}
if (FD_ISSET(my_fd, &fd_set1)) //判断是否来自自定义句柄
{
memset(buf, 0, sizeof(buf));
read(my_fd, buf, sizeof(buf));
printf("read my_fd buf=%s\n", buf);
}
}
else if(ret == 0) //select最后一个参数struct timeval*timeout为NULL,表示无限等待,因此不会超时
{
perror("time out select\n");
}
else
{
perror("error select\n");
}
}
return NULL;
}
int main(int argc, char const *argv[]){ int ret = -1; pthread_t pthread_t1; ret = pthread_create(&pthread_t1, NULL, (void *)poll_thread, NULL); //创建线程 if(ret != 0) { perror("pthread_create"); return -1; } ret = pthread_join(pthread_t1, NULL); //等待线程结束 if(ret != 0) { perror("pthread_join error"); } printf("end.\n"); return 0;}