美文网首页Linux驱动
L5. 等待队列 wait_queue

L5. 等待队列 wait_queue

作者: 开源519 | 来源:发表于2020-06-24 11:08 被阅读0次

1. 基础介绍

等待队列很早就作为一个基本的功能单位存在linux内核中,它以队列为基础数据结构,与进程调度机制紧密配合,能够用于实现内核中的异步事件通知机制。等待队列也可以用来同步对系统资源的访问。在使用时将其当做成一个普通队列数据结构,只不过等待队列是若干个休眠进程的集合,且内核自己实现了此队列初始化队列、入队列、出队列的一系列API,在使用时只需要调用系统的API即可。
简单的理解等待队列: 一个休眠进程的队列,等待特定事件的唤醒。

2 等待队列的部分概念

等待队列头:
等待队列头,顾名思义是等待队列的头部。一个等待队列有一个等待队列头,其他进程唤醒时,只将一个等待队列头的第一个休眠进程唤醒。

等待队列项:
等待队列头就是一个等待队列的头部,每个访问设备的进程都是一个队列项,当设备不可用的时候就要将这些进程对应的等待队列项添加到等待队列里面。

假设一个场景: 全年级同学在操场集合领书,不同的班级在一队(等待队列)。当叫到哪个班级时,该班级的第一位同学上来领书(队列唤醒),没叫到名字的同学原地等待(休眠进程,等待队列项)。此时班级就是一个等待队列头。相同班级的同学组成的队列就是等待队列。

3. 内核提供的队列操作API

3.1 等待队列头:

结构体原型:

struct __wait_queue_head {
    spinlock_t lock;
    struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

等待队列头初始化:

#if 0
//静态初始化
DECLARE_WAIT_QUEUE_HEAD(name); 
#else
//动态初始化
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
#endif

3.2等待队列项:

结构体原型:

struct __wait_queue {
    unsigned int flags;
    void *private;
    wait_queue_func_t func;
};
typedef struct __wait_queue wait_queue_t;

等待队列项定义:

DECLARE_WAITQUEUE(name, tsk)

3.3 添加移除等待队列项

当前进程,先将其休眠(任务调度),然后加入到等待队列,便于其他进程唤醒;进程在唤醒后,就需要移出等待队列。

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

3.4 睡眠

自动睡眠
Linux 内核中睡眠的最简单方式是一个宏定义, 称为 wait_event(有几个变体); 它结合了处理睡眠的细节和进程在等待的条件的检查. wait_event 的形式是:

queue 是等待队列头,condition 是条件,如果调用 wait_event 前 condition == 0 ,则调用 wait_event 之后,当前进程就会休眠,反之不会休眠。

wait_event(queue, condition);               将当前进程进程的状态设置为 TASK_UNINTERRUPTIBLE   ,然后 schedule()

wait_event_interruptible(queue, condition);                          TASK_INTERRUPTIBLE     ,然后 schedule()

wait_event_timeout(queue, condition, timeout);                       TASK_UNINTERRUPTIBLE   ,然后 schedule_timeout()

wait_event_interruptible_timeout(queue, condition, timeout);         TASK_INTERRUPTIBLE     ,然后 schedule_timeout()

TASK_INTERRUPTIBLE 与 TASK_UNINTERRUPTIBLE 区别在于,它的休眠是否会被信号中断,别的进程发来一个信号比如 kill ,TASK_INTERRUPTIBLE 就会醒来去处理。然而 TASK_UNINTERRUPTIBLE 不会。schedule(),进程调度,而schedule_timeout()进行调度之后,一定时间后自动唤醒(超时唤醒),若唤醒后,condition仍然为假,则继续睡眠,反之执行。

手动睡眠

DECLARE_WAITQUEUE(name, tsk)  创建一个等待队列:
tsk一般为当前进行current. 这个宏定义并初始化一个名为name的等待队列.
 将等待队列头 加入/移除 等待队列:
        void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
        void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
        void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
设置进程状态:
        set_current_state(TASK_INTERRUPTIBLE) 等
进程调度:  
        schedule() 或者 schedule_timeout()

还是用自动睡眠较为方便。

3.4 唤醒

当进程进入等待队列休眠时,其他进程可以主动叫等待队列头唤醒首个等待队列项。若为自动睡眠,先判断condition:若为真则执行,否则继续睡眠。

void wake_up(wait_queue_head_t *q)
void wake_up_interruptible(wait_queue_head_t *q)

总结:

笔者在最开始学习时,感觉其与信号量的作用似乎相似。最后经过思考,总结出不同。
信号量 : 其作用在于保护临界区,即临界区被占用时,其他访问该临界区的被动线程休眠。待信号量释放以后,其次的线程才可以访问。
等待队列: 是将当前进程先休眠,直到该进程被其他进程唤醒才可执行,且有超时唤醒功能。

相关文章

  • L5. 等待队列 wait_queue

    1. 基础介绍 等待队列很早就作为一个基本的功能单位存在linux内核中,它以队列为基础数据结构,与进程调度机制紧...

  • 内核线程同步之wait_queue

    在《内核线程同步之completion》一文中说到completion完成量也是基于wait_queue等待队列机...

  • Select & Epoll原理

    预备知识 等待队列 等待队列有一个等待队列头,其他加入这个等待队列的需要加在这个头上。 需要加入等待队列的话,可以...

  • AQS源码解析

    等待队列中线程出队列时机 总的来说,一个线程获取锁失败了,被放入等待队列,acquireQueued会把放入队列中...

  • 等待队列

    工作队列和等待队列的区别 1.work queue 是一种bottom half,中断处理的后半程,强调的是动态的...

  • 等待队列

    等待队列 表示一组睡眠的进程,当某一条件为真时,由内核唤醒他们 在 Linux 中, 一个等待队列由一个"等待队列...

  • 等待队列

    等待队列概念以及使用 一、概述等待队列在内核中有很多用途,尤其在中断处理、进程同步及定时。等待队列实现事件上的条件...

  • Day30

    AQS 同步等待队列 & 条件等待队列 ReentrantLock同步执行,类似synchronized可重入 s...

  • 5、阻塞队列(BlockingQueue)和同步队列(Synch

    队列:FIFO(先进先出)阻塞: 写入:如果队列满了,就必须阻塞等待 读取:如果队列为空,必须阻塞等待生产。160...

  • AbstractQueuedSynchronizer (AQS)

    双队列 在AQS中,存在两个队列 等待队列:用于挂起当前线程,等待某个条件满足后唤醒或是被中断。 同步队列:多线程...

网友评论

    本文标题:L5. 等待队列 wait_queue

    本文链接:https://www.haomeiwen.com/subject/embhfktx.html