1.1 简介
阻塞操作是指在执行设备操作时若不能获得资源则挂起进程, 直到满足可操作的条件后再进行操作。 被挂起的进程进入休眠状态, 从 CPU 调度器的运行队列中移走, 直到等待的条件被满足。 而非阻塞操作的进程在获取不到资源时不会进入睡眠状态, 它或者放弃获取资源, 或者不停地查询, 直到资源获取为止。
1.2 进程的状态介绍
linux 将进程分成如下的五种状态:
1.TASK_RUNNING : 进程运行状态。进程可以被调度为当前进程
2.TASK_INTERRUPTIBLE : 信号可中断的睡眠状态。处于该状态在所需资源有效时被唤醒,也可以通过信号或者定时终端唤醒
3.TASK_UNINTERRUPTIBLE : 不可中断的睡眠状态。处于该状态的进程仅当所需资源有效时被唤醒。
4.TASK_ZOMBIE : 僵尸状态,表示进程结束已设防资源,但是task_struct 仍未释放
5.TASK_STOPPED : 进程暂停状态。处于该状态的进程需要通过其他进程的信号才能被唤醒
PS : 上述的所有中断指的都是软中断
Tip: 1.进程调度函数schedule(void) ,让出CPU使用权
2.设置进程状态函数 set_current_state(state)
1.3 等待队列
linux 系统中,实现阻塞的I/O操作可以通过等待队列实现。一个等待队列由一个“等待队列头”来管理。等待队列头是一个wait_queue_head_t类 型 的 结 构 , 定 义 在 <linux/wait.h>中.一个等待队列头可被定义和初始化。
定义方法分成两种(静态和动态)
静态定义 : DECLARE_WAIT_QUEUE_HEAD(name); //
这里的name 就是要定义的队列头变量名
原型在linux/wait.h中 :
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
动态定义 : wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
与等待队列的相关调用:
1)休眠进程(不可中断)
宏原型: #define wait_event(wq, condition)
原理: 让进程在等待队列头上休眠。在等待队列中睡眠直到 condition 为真。在等待的期间,
进 程会被置TASK_UNINTERRUPTIBLE(不可中断)进入睡眠,直到 condition 变量变为
真。每次进程被唤醒的时候都会检查 condition 的值。
注意: 这里不可中断指的是软中断 !! 就是信号发送会进行阻塞,不会立即执行。
例如此时若 收到ctrl+c 的信号,程序不会立即关掉,而是等待到条件为真的时
候才会继续进行。
2)休眠进程(可中断)
宏原型 #define wait_event_interruptible(wq, condition)
原理: 由名字可以大概推出唤醒的条件与上面不同之处,该宏定义所导致的进程休眠可以被中
断打断。就是该进程在休眠的时候可以接受软中断。(外部信号 crtl +c )。即当进程休
眠的时候接受到信号crtl+c会立即结束进程。
3)休眠进程(可以设置超时时间)(可中断)
宏原型: #define wait_event_interruptible_timeout(wq, condition, timeout)
由标题可以理解,比上述的可中断多了超时控制,即休眠到一定时间会自己退出休眠
状态,执行下面的程序。 单位是节拍(jiffies) , 5*HZ就是5秒
4)休眠进程(可以指定时间)(不可中断)
宏原型 :#define wait_event_timeout(wq, condition, timeout)
基本同上,不可中断。