带您进入内核开发的大门内核中的等待队列

北京皮肤科医院网站 http://m.39.net/pf/a_9204079.html

配套的代码可以从本号的github下载,由于百度将网址看作广告,所以请如有需要的请在下面留言。

等待队列是一种基于资源状态的线程管理的机制,它可以使线程在资源不满足的情况下处于休眠状态,让出CPU资源,而资源状态满足时唤醒线程,使其继续进行业务的处理。

等待队列(waitqueue)用于使线程等待某一特定的事件发生而无需频繁的轮询,进程在等待期间睡眠,在某件事发生时由内核自动唤醒。它是以双循环链表为基础数据结构,与进程的休眠唤醒机制紧密相联,是实现异步事件通知、跨进程通信、同步资源访问等技术的底层技术支撑。

基本接口

wait_queue_head_t使用等待队列时,最基本的数据结构是structwait_queue_head_t,也就是等待队列头,这个可以理解为等待队列的实体。队列头中包含一个双向链表,用于记录在该等待队列中处于等待状态的线程等信息。该结构体的定义如下:

可以通过宏定义DECLARE_WAIT_QUEUE_HEAD直接定义一个队列头变量,并完成初始化,该宏定义如下:

或者是通过结构体wait_queue_head_t定义后,调用函数init_waitqueue_head进行初始化。虽然方式不同,但基本原理是一样的,主要是对结构体内自旋锁和链表的初始化。

wait_event函数wait_event用于在某个线程中调用,当调用该函数时,如果参数中的条件不满足,则该线程会进入休眠状态。下面代码是该函数的定义:

wake_up函数wake_up用于对处于阻塞状态的线程进行唤醒,其参数就是队列头。如下是该函数的定义,我们这里暂时不展开介绍。

了解了上面1个数据结构及相关函数后就可以使用等待队列了,当然只是基本的使用。

示例程序

我们这里给出一个示例程序,程序很简单。示例程序中有2个线程,分别是服务线程和客户线程。其中服务线程起来后会检查条件是否满足,并视情况进入休眠状态。而客户进程会每隔5秒将条件变成可用状态,并唤醒服务线程。

等待队列的原理

关于等待队列的原理,有3点需要重点说明,理解了这几点,也就能够比较清晰的理解等待队列的原理。这3点分别是数据结构、等待函数和唤醒函数。我们这里还是从结构体说起。这里主要有2个结构体,前面已经有所介绍。其中

wait_queue_head

是等待队列头,定义如下:

这里主要是双向链表,所有处于等待状态的线程都被加入到该双向链表中。等后续唤醒时根据该链表中的数据进行唤醒。另外一个数据结构是wait_queue_entry,该结构体是一个等待项,这个结构体对于普通用户通常不必关系,因为内核的API对其进行了封装。

其中前一个结构体的head成员和后一个结构体的entry成员配合,形成所谓的双向链表。我们先看一下其大概的结构,具体如下图所示。

关于等待函数关于等待函数,前面给出了一部分定义,下面我们继续深入介绍。在介绍之前,我们先介绍一下其大概流程,本质上就是将当前线程状态设置为TASK_UNINTERRUPTIBLE状态,然后调用schedule函数将本线程调度出去。理解了这个原理,代码就很容易理解,下面是函数的实现:

直接调用的___wait_event函数,注意观察一下这个函数的几个参数,其中TASK_UNINTERRUPTIBLE是目标状态,而schedule则是在内部要调用的函数。

这个函数里面所调用的函数的具体实现就不再解释了,代码贴过来太冗余了,本身也比较简单。

关于唤醒函数唤醒函数前面也做过简单介绍,我们这里直接进入主体,介绍其实现函数。

具体实现在函数__wake_up_


转载请注明:http://www.92nongye.com/xxnr/xxnr/204626768.html