poll & epoll & select

来源:互联网 发布:权志龙直播软件 编辑:程序博客网 时间:2024/06/03 17:08

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      -1static 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)      //判断是否为键盘的输入事件            {           
                memset(buf, 0, sizeof(buf));
                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;}
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;}