#导入Word文档图片# 阻塞与非阻塞IO操作

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#导入Word文档图片# 阻塞与非阻塞IO操作相关的知识,希望对你有一定的参考价值。


Linux内核版本:linux3.5

1.1 简介

阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,从CPU调度器的运行队列中移走, 直到等待的条件被满足。 而非阻塞操作的进程在获取不到资源时不会进入睡眠状态, 它或者放弃获取资源, 或者不停地查询, 直到资源获取为止。

驱动程序通常需要提供这样的能力:当应用程序进行 read()、 write()等系统调用时,若设备的资源不能获取,而用户又希望以阻塞的方式访问设备, 驱动程序应在设备驱动的 xxx_read()、 xxx_write()等操作中将进程阻塞直到资源可以获取, 此后, 应用程序的 read()、 write()等调用才返回, 整个过程仍然进行了正确的设备访问,用户并没有感知到;若用户以非阻塞的方式访问设备文件, 则当设备资源不可获取时, 设备驱动的 xxx_read()、 xxx_write()等操作应立即返回, read()、 write()等系统调用也随即被返回。​

阻塞从字面上听起来似乎意味着低效率,实则不然,如果设备驱动不阻塞,则用户想获取设备资源只能不停地查询,这反而会无谓地耗费 CPU 资源。 而阻塞访问时,不能获取资源的进程将进入休眠, 它将 CPU 资源让给其他进程。​

因为阻塞的进程会进入休眠状态,因此,必须确保有一个地方能够唤醒休眠的进程。唤醒进程的地方最大可能发生在中断里面,因为硬件资源获得的同时往往伴随着一个中断。​

1.2 进程的状态

Linux将进程状态描述为如下五种:

TASK_RUNNING :可运行状态。处于该状态的进程可以被调度执行而成为当前进程。

TASK_INTERRUPTIBLE :信号可中断的睡眠状态。处于该状态的进程在所需资源有效时被唤醒,也可以通过信号或定时中断唤醒(因为有signal_pending()函数)。


TASK_UNINTERRUPTIBLE:不可中断的睡眠状态。处于该状态的进程仅当所需资源有效时被唤醒。

TASK_ZOMBIE :僵尸状态。表示进程结束且已释放资源,但其task_struct仍未释放。

TASK_STOPPED :暂停状态。处于该状态的进程通过其他进程的信号才能被唤醒。


进程调度函数,让出CPU使用权:

schedule(void)


设置进程的状态(一般设置的状态为以上定义的五种):

set_current_state(state);


1.3 等待队列

在 Linux 中, 一个等待队列由一个"等待队列头"来管理, 一个 wait_queue_head_t 类型的结构, 定义在<linux/wait.h>中. 一个等待队列头可被定义和初始化。

使用:

DECLARE_WAIT_QUEUE_HEAD(name);


或者动态定义如下:

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);


等待队列可以用来同步对系统资源的访问,前面所讲述的信号量在内核中也依赖等待队列来实现。

1.3.1 等待队列头休眠相关的API函数

1.3.1.1 静态初始化等待队列头

宏原型

#define DECLARE_WAIT_QUEUE_HEAD(name) \\

wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

宏功能

静态初始化数据。定义并且初始化一个等待队列头结构变量,名字为name。

宏参数

name要定队列头变量名

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h


1.3.1.2 动态初始化等待队列头

宏原型

/*动态初始化等待队列头*/

#define init_waitqueue_head(q)\\

do \\

static struct lock_class_key __key;\\

\\

__init_waitqueue_head((q), #q, &__key);\\

while (0)

宏功能

动态初始一个等待队列头

宏参数

q要定队列头变量名指针

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h

示例

wait_queue_head_t wq; 定义全局变量)

init_waitqueue_head(&wq); 在其他函数内调用初始)

上面这两行等效于:DECLARE_WAIT_QUEUE_HEAD(wq)


1.3.1.3 休眠进程(不可中断)

宏原型

#define wait_event(wq, condition) \\

do \\

if (condition)\\

break;\\

__wait_event(wq, condition);\\

while (0)

宏功能

进程在等待队列头上休眠。在等待会列中睡眠直到condition为真。在等待的期间,进程会被置为TASK_UNINTERRUPTIBLE(不可中断)进入睡眠,直到condition变量变为真。每次进程被唤醒的时候都会检查condition的值。

注意:这里的中断指的是信号(软中断)。

比如:ctrl+c信号等。 信号会进行阻塞,如果在进程睡眠时发送了信号给进程,这时进程是收不到信号的,但是信号并没有消失,当进程被唤醒的时候就会收到信号!

宏参数

wq:要休眠的队列头condition:休眠的条件,0时休眠,否则不进入休眠,不能直接传递数字,要传递变量。

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h


1.3.1.4 休眠进程(可中断)

宏原型

#define wait_event_interruptible(wq, condition)\\

(\\

int __ret = 0;\\

if (!(condition))/*判断--->条件为假的时候进入休眠*/\\

__wait_event_interruptible(wq, condition, __ret);\\

__ret;\\

)

宏功能

进程在等待队列头上休眠。wait_event()的区别是调用该宏在等待的过程中当前进程会被设置为TASK_INTERRUPTIBLE休眠状态.在每次被唤醒的时候,首先检查condition是否为真,如果为真则返回,否则检查如果进程是被信号唤醒,会返回-ERESTARTSYS错误码.如果是condition为真,则返回0.

宏参数

wq:要休眠的队列头condition:休眠的条件,0时休眠,否则不进入休眠

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h


1.3.1.5 休眠进程(可以指定时间)(不可中断)

宏原型

#define wait_event_timeout(wq, condition, timeout)\\

(\\

long __ret = timeout;\\

if (!(condition)) \\

__wait_event_timeout(wq, condition, __ret);\\

__ret;\\

)

宏功能

进程在等待队列头上休眠。与wait_event()类似.不过如果所给的睡眠时间为负数则立即返回.如果在睡眠期间被唤醒,且condition为真则返回剩余的睡眠时间,否则继续睡眠直到到达或超过给定的睡眠时间,然后返回0.

宏参数

wq:要休眠的队列头

condition:休眠的条件,0时休眠,否则不进入休眠

timeout超时时间,单位是时钟节拍,一般使用1 * HZ (1秒样形式定义。

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h


1.3.1.6 休眠进程(可以设置超时时间)(可中断)

宏原型

#define wait_event_interruptible_timeout(wq, condition, timeout)\\

(\\

long __ret = timeout;\\

if (!(condition))\\

__wait_event_interruptible_timeout(wq, condition, __ret); \\

__ret;\\

)

宏功能

进程在等待队列头上休眠。wait_event_timeout()类似

如果在睡眠期间被信号打断则返回-ERESTARTSYS错误码

宏参数

wq:要休眠的队列头

condition:休眠的条件,0时休眠,否则不进入休眠

timeout超时时间,单位是时钟节拍,一般使用5 * HZ (5秒)这样形式定义。

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h


1.3.2唤醒进程相关的函数API

上面介绍的是进程休眠函数接下来就是唤醒进程的函数。

1.3.2.1 唤醒休眠的进程(中断与非中断都可以)

宏原型

#define wake_up(x)__wake_up(x, TASK_NORMAL, 1, NULL)

宏功能

可唤醒处于TASK_INTERRUPTIBLETASK_UNINTERUPTIBLE状态的进程,

wait_event/wait_event_timeout成对使用。

宏参数

x:要唤醒的队列头指针 ;

所在头文件

include\\linux\\wait.h

定义文件

include\\linux\\wait.h

示例:wake_up(&wq)

说明:如果驱动里阻塞了5个进程,只会唤醒第一个休眠的进程,按照先后顺序。

1.3.2.2 唤醒休眠的进程(可中断类型)

宏原型

#define wake_up_interruptible(x)__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

宏功能

NIO之阻塞IO与非阻塞IO

Linux设备驱动基础03之阻塞与非阻塞IO

Linux设备驱动基础03之阻塞与非阻塞IO

Linux设备驱动基础03之阻塞与非阻塞IO

Linux设备驱动基础03之阻塞与非阻塞IO

Linux IO模型

(c)2006-2024 SYSTEM All Rights Reserved IT常识