天天看点

linux阻塞和休眠,Linux设备驱动之阻塞与非阻塞IO

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

Linux驱动程序中使用等待队列(wait_queue)来实现阻塞进程的唤醒。

静态方法定义并初始化一个等待队列头:

DECLARE_WAIT_QUEUE_HEAD(name);

或者使用动态方法:

wait_queue_head mane;

init_watiqueue_head(&name);

等待事件:

conditions为任意一个布尔值,若为真,进程被唤醒,否则休眠。后两个版本只会等待给定的时间,到期时,这两个宏都会返回0值,而无论conditions如何求值。

wait_event(queue, conditions);进程将被置于非中断休眠,这通常不是我们所期望的

wait_event_interruptible(queue, conditions);最好选择此方式,它可以被信号中断。返回非0表示被某个信号中断。

wait_event_timeout(queue, conditions,timeout);

wait_event_interruptible_timeout(queue, conditions,timeout);

唤醒:

阻塞的另外一半是唤醒。其它的某个执行线程(可能是另一个进程或者为断处理例程)必须为我们执行唤醒,因为我们的进程正在休眠中。用来唤醒休眠进程的基本函数是wake_up,它有多种形式:

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);只会唤醒那些执行中可中断休眠的进程。

在实践中,约定作法是wait_event时使用wake_up,使用wait_event_interruptible时使用 wake_up_interruptible。

示例代码:任何试图从该设备读取的进程均被置于休眠,只要某个进程向该设备写入,所有的休眠的进程将被唤醒。

static DECLARE_WAIT_QUEUE_HEAD(wq);

static int flag=0;

ssize_t sleepy_read(struct file *filp,char __user *buf,size_t count,loff_t *pos)

{

wait_event_interruptible(wq,flag!=0);

flag = 0;

.....

.....

return 0;

}

ssize_t sleepy_write(struct file *filp,char __user *buf,size_t count,loff_t *pos)

{

flag = 1 ;

wake_up_interruptible(&wq);

return count;

}