嵌入式内核及驱动开发之学习笔记(九) 多路复用+中断实现读取数据

举报
王建峰 发表于 2021/11/19 02:16:35 2021/11/19
【摘要】 使用阻塞模型虽然可以避免等待数据过程中,CPU对进程的消耗,但是仅仅是为了等待这一个结果,就让进程进入休眠,对于还要进行其他IO操作的进程而言太“奢侈”。所以引入多路复用的概念,解决这个问题。 非阻塞:立即返回结果,如果想得到期望的结果,要不停的调用这个方法(轮询),非常耗费资源 阻塞:没有得到真正的数据前,不返回结果。此时,进程进...

使用阻塞模型虽然可以避免等待数据过程中,CPU对进程的消耗,但是仅仅是为了等待这一个结果,就让进程进入休眠,对于还要进行其他IO操作的进程而言太“奢侈”。所以引入多路复用的概念,解决这个问题。

非阻塞:立即返回结果,如果想得到期望的结果,要不停的调用这个方法(轮询),非常耗费资源

阻塞:没有得到真正的数据前,不返回结果。此时,进程进入阻塞(休眠)态,直到有数据唤醒进程,这个过程不耗资源。

多路复用:和原理和阻塞类似,不过多路复用是同时进行多个IO读写操作。这样就减少了在等待时间上的浪费,提高效率。

 

 

多路复用要对文件描述符进行操作,在应用层上进行实现。关于多路复用在应用层上的使用,之前我有总结过一份笔记。这里使用poll函数完成;应用中使用poll对设备文件进行了监控,那么设备驱动就必须实现poll接口。所以...

  1. poll函数实现对标准输入流(按键)与设备输入流(按键)的监控
  2. 在设备驱动中实现poll的接口

Linux环境下使用`man 2 poll`查看poll函数的介绍,程序包含头文件poll.h

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数1: 表示多个文件描述符集合
    struct pollfd描述的是文件描述符到信息
    struct pollfd {
       int   fd;  //文件描述符
       short events;   //希望监控fd的什么事件:读,写,出错
                    POLLIN 读,
                    POLLOUT 写,
                    POLLERR出错
       short revents;    //结果描述,表示当前的fd是否有读,写,出错
                    //用于判断,是内核自动赋值
                    POLLIN 读,
                    POLLOUT 写,
                    POLLERR出错
    };
参数2:被监控到fd的个数
参数3: 监控的时间:
            正: 表示监控多少ms
            负数: 无限的时间去监控
            0: 等待0ms,类似于非阻赛
返回值: 负数:出错
        大于0,表示fd中有数据
        等于0: 时间到 

 

应用程序


  
  1. //key_test.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <poll.h>
  10. struct key_event{
  11. int code; // 按键的类型
  12. int value; // 状态
  13. };
  14. #define KEY_ENTER 28
  15. int main(int argc, char *argv[])
  16. {
  17. int ret;
  18. char in_buf[128]; //接收标准输入数据
  19. struct key_event event; //接收按键设备数据
  20. int fd = open("/dev/key0", O_RDWR);
  21. if(fd < 0)
  22. {
  23. perror("open");
  24. exit(1);
  25. }
  26. //描述2个文件描述符,标准输入0 和 按键设备结点fd
  27. struct pollfd pfd[2];
  28. pfd[0].fd = fd; //监控按键设备
  29. pfd[0].events = POLLIN;
  30. pfd[1].fd = 0; //标准输入
  31. pfd[1].events = POLLIN;
  32. while(1)
  33. {
  34. ret = poll(pfd, 2, -1); // 多路复用 poll 同时监控按键与标准输入
  35. printf("ret = %d\n", ret);
  36. if(ret > 0)
  37. {//表示有数据
  38. if(pfd[0].revents & POLLIN)
  39. {//按键设备
  40. //读设备结点中的数据
  41. read(pfd[0].fd, &event, sizeof(struct key_event));
  42. if(event.code == KEY_ENTER)
  43. {
  44. if(event.value)
  45. {
  46. printf("APP__ key enter pressed\n");
  47. }else
  48. {
  49. printf("APP__ key enter up\n");
  50. }
  51. }
  52. }
  53. if(pfd[1].revents & POLLIN)
  54. {//标准输入
  55. fgets(in_buf, 128, stdin);
  56. printf("in_buf = %s\n", in_buf);
  57. }
  58. }else{
  59. perror("poll");
  60. exit(1);
  61. }
  62. }
  63. close(pfd[0].fd);
  64. return 0;
  65. }

 

设备驱动文件

1.在file_operations中 poll指向key_drv_poll函数


  
  1. const struct file_operations key_fops = {
  2. .open = key_drv_open,
  3. .read = key_drv_read,
  4. .write = key_drv_write,
  5. .release = key_drv_close,
  6. .poll = key_drv_poll,
  7. };

2.在key_drv_poll函数中实现接口


  
  1. unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
  2. {
  3. // 返回一个mask值
  4. unsigned int mask;
  5. // 调用poll_wait,将当前到等待队列注册系统中
  6. poll_wait(filp, &key_dev->wq_head, pts);
  7. // 1,当没有数据到时候返回一个0
  8. if(!key_dev->key_state)
  9. mask = 0;
  10. // 2,有数据返回一个POLLIN
  11. if(key_dev->key_state)
  12. mask |= POLLIN;
  13. return mask;
  14. }

 

最终结果

文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/feit2417/article/details/84192417

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。