08、LinuxC -- IO多路复用 poll函数

poll函数用于监听一组文件描述符,等待它们准备就绪。当有事件发生时,它返回有动静的文件描述符数量。参数包括结构体数组fds、元素个数nfds和超时时间timeout。当无事件发生时,poll会阻塞,直到超时或有事件发生。返回值表示成功响应的文件描述符数量。在示例代码中,程序同时监听键盘和鼠标输入。poll的优点是没有最大文件描述符限制,但缺点是全盘轮询可能导致效率下降,且涉及大量数据拷贝。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        监听集合没无动静,如果没有动静就阻塞,如果有动静就成功返回,返回值为集合中有动静的fd的数量。

poll 函数原型
        int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数:
        fds:这个参数写为struct pollfd fds[ ] 更好理解,第一个参数要求传递一个 struct poll fd 结构体数组。这个数组就相当于select的文件描述符集合,只不过select是使用fd_set来定义的,而poll的集合是一个数组。
struct pollfd的成员:
struct pollfd

{
         int   fd;      :文件描述符
         short events;  :设置我们希望发生的事件,比如读事件,这个需要我们自己设置
         short revents; :实际发生的事件,比如读事件,由poll机制自己设置
};

events   说明
1、POLLIN 普通或优先级带数据可读
2、POLLRDNORM  普通数据可读
3、POLLRDBAND  优先级带数据可读
4、POLLPRI高优先级数据可读
5、POLLOUT普通数据可写
6、POLLWRNORM  普通数据可写
7、POLLWRBAND  优先级带数据可写
8、POLLERR发生错误
9、POLLHUP发生挂起
10、POLLNVAL  描述字不是一个打开的文件

poll 监听时如果没有动静就阻塞,有动静就不再阻塞,返回有动静的fd的数量。

如何知道是那些fd有动静?
        如果文件描述符“发生的事件”==“实际事件”,就说明希望的事件来了,就是对fd进行相应的“读或写”操作。        
        

        nfds:数组的元素个数。
        timeout:超时时间,如果写的是
               -1:不设置超时,如果集合没有动静就一直阻塞下去,直到poll函数被信号中断(唤醒)或者集合有动静为止                      
               非-1值:比如3000(3000微妙),表示将超时时间设置为3秒也就是说poll超时时间的单位时微妙。   

返回值:

        返回-1:说明函数调用失败,errno被设置。

如果是被信号中断从而导致出错返回-1时,errno被设置为EINTR,
如果不想被中断,要么重启poll的调用,要么忽略或者屏蔽这些信号。                    
        0:超时时间到,而且没有文件描述符有动静。
        大于0:返回有响应的文件描述符的数量。

demo代码: 同时读键盘和鼠标

#include <stdio.h>
#include <stdlib.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>

int main(int argc, char const *argv[])
{
    int fd;

    if ((fd = open("/dev/input/mouse0", O_RDWR | O_CREAT, 0655)) < 0)
    {
        perror("open file error!");
        exit(1);
    }

    struct pollfd fds[2];

    fds[0].fd = 0;
    fds[0].events = POLLIN;

    fds[1].fd = fd;
    fds[1].events = POLLIN;

    while (1)
    {
        int ret = poll(fds, 2, -1);
        for (int i = 0; i < 2; i++)
        {
            if (fds[i].events == fds[i].revents)
            {
                if (fds[i].fd == 0)
                {
                    char buffer[1024];

                    read(fds[i].fd, buffer, sizeof(buffer));

                    printf("buffer = %s\n", buffer);
                }

                else if (fds[i].fd == fd)
                {
                    int cor;

                    read(fds[i].fd, &cor, sizeof(cor));

                    printf("cor = %d\n", cor);
                }

                if (--ret == 0)
                {
                    break;
                }
            }
        }
    }

    return 0;
}

执行结果:

root@GodFather:/home/superlan/C_Language/advanced_IO_operation# ./a.out 
cor = 8486696
cor = 8480552
cor = 12255272
cor = 520
cor = 264
hello
buffer = hello

^C
root@GodFather:/home/superlan/C_Language/advanced_IO_operation# 

poll 的优缺点

        解决 select 监听文件描述符受限的问题,通过采用链表的方式保存文件描述符

优点

        poll 没有最大文件描述符限制(使用链表的方式存储 fd)

缺点:

        因为无法获取具体哪个文件描述符发生变化,只能进行全盘轮询,随着监听的文件描述符增多,效率下降;

        所监听的文件描述符都必须从用户空间传入内核空间进行监听,涉及到大量的数据拷贝,效率低。
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值