zoukankan      html  css  js  c++  java
  • 10、驱动中的阻塞与非阻塞IO

        阻塞,就是在获取资源的时候,不能获取到,那么就会将当前的进程挂起(睡眠,也就是将当前进程从调度器拿走了,不会调度当前进程),直到满足条件为止再进行操作。相反,非阻塞,就是即使不能获取到资源,非阻塞的进程是,要么是直接放弃,要么就不停地的进行查询,直到满足为止。

        当上层 read 或者 write 的时候,希望是阻塞地去获取资源时候,那么底层的驱动,就应该去以阻塞的方式去实现;而当是希望以非阻塞的方式的时候,当不慢满足的时候,就立即返回,且应用层收到 –EAGAIN 的返回值。

    1、驱动中的阻塞

       底层驱动的阻塞操作,是借助了 等待队列的方式进行实现的,定义一个等待队列头,本质上是一个双向链表,队列的后续挂接了不同的节点,这些节点就是等待的任务,当在程序的某一个位置唤醒了等待队列头的时候,那么挂接在等待队列头的双向链表的任务节点,都会被唤醒。

    1.1、API

    (1)定义等待队列头

    wait_queue_head_t myqueue; 

    (2)初始化队列头

    init_waitqueue_head(&myqueue);

        其实可以通过定义和初始化一体的宏代码: DECLARE-WAITQUEUQ(name)    name. 就是定义以及被初始化的头部

    (3)定义等待任务

        DECLARE_WAITQUEUE(name, tsk)

        定义了一个等待任务,name。而 tsk 是任务进程,一般是设置为 current,也就是设置为当前的进程。

    (4)添加/删除队列

        void add_wait_queue(wait_queue_head_t *myqueue, wait_queue_t * wait);

        void remove_wait_queue(wait_queue_head_t *myqueue, wait_queue_t * wait)

        将等待队列(wait),添加到 以myqueue 作为头部的,双向链表中,

    (5)等待事件

        wait_event(myqueue, condition)

        将以 myqueue 的队列,全部进行阻塞,等待 condition 为真,不能被打断

        wait_event_interruptible(wq, condition)    ,是先等待的同时,可以被打断

    (6)唤醒队列

    wake_up(wait_queue_head_t *myqueue)

        唤醒等待队列头,会将队列中的所有进程都进行唤醒。

    2、驱动的非阻塞

         驱动中的非阻塞实现,可以通过 struct file 中的 f_flags 标志进行判断,当 f_flags & O_NONBLOCK (因为上次应用的标志位的设置的时候,不仅仅是非阻塞,也有其他的,所以用 与,而不是等号)不等于零的,在资源不能获取的时候,立刻进行返回。还有一种是借助了 select 或者 poll 实习。

    int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

    nfd : 是检测文件描述符中最大的 加一,

    fd_set  : 是检测文件的文件集,可见,可以按照读、写、异常,分开进行检测

    timeout :阻塞时间,

        select 会对指定的文件,进行实时检测,当检测到文件状态的变动,立马返回;没有检测到的时候,就直接进行阻塞,,但是阻塞不是一直进行下去的,阻塞的时间是通过 timeout 指定的时间。超过时间,即使没有检测到,也进行返回

    2.1、文件集的设置

    void FD_CLR(int fd, fd_set *set);   // 清空文件集
    int FD_ISSET(int fd, fd_set *set);  // 检测文件,是否以及被置为到文件集
    void FD_SET(int fd, fd_set *set);  // 将文件描述符,置为到文件集
    void FD_ZERO(fd_set *set);   // 清空

    2.2、底层poll

        当上层调用了select 或者 poll 、epoll 的时候,底层的 poll  被调用,

    unsigned int (*poll) (struct file *, struct poll_table_struct *);

    第一个参数,是被打开文件,相关的参数;第二个参数,是被轮询设备的表格。poll 函数里面,当返回的时候,需要返回以下:

    POLLIN : 表示设备可读,参考是应用层,

    POLLOUT : 表示设备可写,

    POLLERR : 错误

    POLLRDNORM :必须被设置,

    一般是:

    unsigned int (*poll) (struct file *, struct poll_table_struct *)

    {

            if (XXXXX)

               mask |= POLLIN |  POLLRDNORM ;

            else

                 mask |= POLLOUT |  POLLRDNORM ;

    }

  • 相关阅读:
    A*算法研究
    C++实现动态数组
    Sublime Text3括号配对与代码包围效果BracketHighlighter
    SublimeREPL配置Python3开发
    Ubuntu16.04下使用sublime text3搭建Python IDE
    Netbeans使用笔记
    vscode: Visual Studio Code 常用快捷键
    OKR 第一阶段
    浏览器是如何工作的
    javascriptdocument load 和document ready的区别
  • 原文地址:https://www.cnblogs.com/qxj511/p/5483213.html
Copyright © 2011-2022 走看看