• Linux学习第24天:Linux 阻塞和非阻塞 IO 实验(一): 挂起


    Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


            在正式开始今天的笔记之前谈一下工作中遇见的一个问题。

            本篇笔记主要学习Linux 阻塞和非阻塞 IO 实验,主要包括阻塞和非阻塞简介、等待队列、轮询、poll操作、阻塞和非阻塞实验。其中重点内容为阻塞和非阻塞实验。

            本笔记的思维导图如下:

    一、阻塞和非阻塞IO

    1.阻塞和非阻塞简介

            1)阻塞

    1. 1 int fd;
    2. 2 int data = 0;
    3. 3 4
    4. fd = open("/dev/xxx_dev", O_RDWR); /* 阻塞方式打开 */
    5. 5 ret = read(fd, &data, sizeof(data)); /* 读取数据 */

    2)非阻塞

    1. 1 int fd;
    2. 2 int data = 0;
    3. 3 4
    4. fd = open("/dev/xxx_dev", O_RDWR); /* 阻塞方式打开 */
    5. 5 ret = read(fd, &data, sizeof(data)); /* 读取数据 */

            参数“O_NONBLOCK”,表示以非阻塞方式打开设备,这样从设备中读取数据的时候就是非阻塞方式的了。


    2.等待队列

            1)等待队列头

            等待队列头使用结构体wait_queue_head_t 表示:

    1. 39 struct __wait_queue_head {
    2. 40 spinlock_t lock;
    3. 41 struct list_head task_list;
    4. 42 };
    5. 43 typedef struct __wait_queue_head wait_queue_head_t;

            init_waitqueue_head 函数初始化等待队列头

    void init_waitqueue_head(wait_queue_head_t *q)//参数 q 就是要初始化的等待队列头。

    也可以使用宏 DECLARE_WAIT_QUEUE_HEAD 来一次性完成等待队列头的定义的初始化。


            2)等待队列项

    结构体 wait_queue_t 表示等待队列项,结构体内容如下:

    1. struct __wait_queue {
    2. unsigned int flags;
    3. void *private;
    4. wait_queue_func_t func;
    5. struct list_head task_list;
    6. };
    7. typedef struct __wait_queue wait_queue_t;

            宏DECLARE_WAITQUEUE 就是给当前正在运行的进程创建并初始化了一个等待队列项。

    DECLARE_WAITQUEUE(name, tsk)

            name 就是等待队列项的名字, tsk 表示这个等待队列项属于哪个任务(进程),一般设置为
    current , 在 Linux 内 核 中 current 相 当 于 一 个 全 局 变 量 , 表 示 当 前 进 程 。

            3)将队列项添加/删除队列头

            只有添加到等待队列头中以后进程才能进入休眠态。等待队列项添加 API 函数如下:

    1. void add_wait_queue(wait_queue_head_t *q,
    2. wait_queue_t *wait)

            等待队列项移除 API 函数如下:

    1. void remove_wait_queue(wait_queue_head_t *q,
    2. wait_queue_t *wait)

            4)等待唤醒

    1. void wake_up(wait_queue_head_t *q)
    2. void wake_up_interruptible(wait_queue_head_t *q)

           wake_up_interruptible 函数只能唤醒处于 TASK_INTERRUPTIBLE 状态的进程。


    5)等待事件

    函数描述
    wait_event(wq, condition)

     
    等待以 wq 为等待队列头的等待队列被唤醒,前
    提是 condition 条件必须满足(为真),否则一直阻
    塞 。 此 函 数 会 将 进 程 设 置 为
    TASK_UNINTERRUPTIBLE 状态

     
    wait_event_timeout(wq, condition, timeout)
    功能和 wait_event 类似,但是此函数可以添加超
    时时间,以 jiffies 为单位。此函数有返回值,如
    果返回 0 的话表示超时时间到,而且 condition
    为假。为 1 的话表示 condition 为真,也就是条
    件满足了。

     
    wait_event_interruptible(wq, condition)
    与 wait_event 函数类似,但是此函数将进程设置
    为 TASK_INTERRUPTIBLE,就是可以被信号打
    断。

     
    wait_event_interruptible_timeout(wq,
    condition, timeout)

     
    与 wait_event_timeout 函数类似,此函数也将进
    程设置为 TASK_INTERRUPTIBLE,可以被信号
    打断。

     

    3.轮询【非阻塞】

            1)select函数        

    1. int select(int nfds,
    2. fd_set *readfds,
    3. fd_set *writefds,
    4. fd_set *exceptfds,
    5. struct timeval *timeout)

            fd_set 类型变量的每一个位都代表了一个文件描述符。

    1. void FD_ZERO(fd_set *set)
    2. void FD_SET(int fd, fd_set *set)
    3. void FD_CLR(int fd, fd_set *set)
    4. int FD_ISSET(int fd, fd_set *set)

            2)poll函数

            没有最大文件描述符限制。

    1. int poll(struct pollfd *fds,
    2. nfds_t nfds,
    3. int timeout)

            3)epoll函数

            epoll 就是为处理大并发而准备的。

    int epoll_create(int size)

    返回值: epoll 句柄,如果为-1 的话表示创建失败。

            epoll_ctl 函数向其中添加要监视的文件描述符以及监视的事件, epoll_ctl 函数原型如下所示:

    1. int epoll_ctl(int epfd,
    2. int op,
    3. int fd,
    4. struct epoll_event *event)

    epoll_wait 函数来等待事件的发生:

    1. int epoll_wait(int epfd,
    2. struct epoll_event *events,
    3. int maxevents,
    4. int timeout)

    4.poll操作

    poll 函数原型如下所示:

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

    poll_wait 函数不会引起阻塞,只是将应用程序添加到 poll_table 中, poll_wait 函数原型如下:

    void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

            参数 wait_address 是要添加到 poll_table 中的等待队列头,参数 p 就是 poll_table,就是
    file_operations 中 poll 函数的 wait 参数。

    二、总结

            本篇笔记主要学习Linux 阻塞和非阻塞 IO 实验,主要包括阻塞和非阻塞简介、等待队列、轮询、poll操作。


    以下内容将在下一篇笔记中进行学习:

    二、阻塞IO实验

    1.硬件原理图分析

    2.实验程序

    3.运行测试

    三、非阻塞IO实验

    1.硬件原理图分析

    2.实验程序

    3.运行测试


    本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

  • 相关阅读:
    Object.defineProperty
    iOS UIKit
    抖音seo矩阵系统源码开发技术
    SpringBoot连接MySQL密码错误,报错:Access denied for user
    XS9950 :一路工规AHD模拟RX
    小程序实现一个全局的loadding效果
    SSM框架之MyBatis入门(Maven工程实现全查功能,快速入门,适合小白)
    FreeRTOS个人笔记-事件
    Android busybox介绍
    路网编辑器技术预研
  • 原文地址:https://blog.csdn.net/jiage987450/article/details/134083067