1、等待队列、完成量、工作队列的使用场景

本文详细介绍了Linux驱动中等待队列、完成量和工作队列的使用方法,以NVMe驱动为例,阐述了它们在处理进程睡眠、事件通知以及异步工作的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这三个机制在Linux驱动及内核中被广泛使用,可以说任何一个内核程序都会用到;虽然它们的原理可能很复杂,但是作为使用者,我们只关心何时及如何使用它。

等待队列

        关键在“等待”二字,它用于使进程(线程)等待某一特定事件的发生(进程在等待期间会睡眠。),在事件发生时由内核唤醒;

        在名称上要区分工作队列,在使用场景上要区分完成量;我们很快就会看到它们的区别。

        等待队列的使用:

        等待队列的使用方式非常简单,我们以NVMe驱动中使用等待队列的方式为例;

        1、 首先定义等待队列头:wait_queue_head_t    state_wq;

        2、然后初始化:init_waitqueue_head(&state_wq);

        3、在需要的位置使进程睡眠:

        wait_event(state_wq,

               nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING) | nvme_state_terminal(ctrl));

        调用wait_event()的进程会在此处睡眠,此函数有两个参数,第一个是定义的等待队列,第二个被唤醒的条件;

        4、在内核其他地方唤醒进程:wake_up_all(&state_wq);

        wake_up_all()唤醒所有睡眠的进程;wake_up()唤醒一个睡眠的进程;在唤醒前,要设置wait_event()的第二个参数为true;

对于使用者来说这四步,这四步就完成了等待队列的使用,工作原理会在后面文章介绍。

完成量

        完成量跟等待队列的使用场景非常类似,其实完成量就是通过等待队列实现的,我们在后续介绍原理的时候看完成量的定义就一目了然了。

        考虑一个场景,如果要等待某件事情,我们知道要用等待队列,但如果我们在开始等待时,事情可能已经发生,这样就永远无法唤醒睡眠的进程了;所以在事情可能已经发生的场景下应该使用完成量。

        完成量就在等待队列的基础上增加一个计数,当事件发生时计数累加;当开始等待事件时先判断计数是否>0,如果>0说明事件已经发生,就不再等待。

        完成量的使用,仍然以NVMe驱动为例:

        1、定义完成量:struct completion     disable_done;

        2、初始化:        init_completion(&disable_done);

        3、等待事件:    wait_for_completion(&disable_done);(如果事件已经发生过了就不再等待,否则进程睡眠)。

        4、当内核其他地方完成事件时:    complete(&ns->disable_done);

        完成量与等待队列的行为完全一致。

工作队列

        在名称上区分于“等待队列”;工作队列用于处理要稍后异步处理的工作,它由内核专门的线程去执行;通常用于中断的“下半部”;

        也就是说工作队列是多线程机制;首先创建一个工作队列,然后加入工作项,这些工作项稍后由内核线程去执行;工作项的执行是在另外线程异步进行的,不会阻塞本线程。

        工作队列的工作方式:(以NVMe驱动为例)

        1、声明一个工作队列:struct workqueue_struct    *nvmet_wq;

        2、创建工作队列:  nvmet_wq = alloc_workqueue("nvmet-wq", WQ_MEM_RECLAIM, 0);

        3、真正工作的是工作项:

                        a)  定义工作项 : struct work_struct    async_event_work;

                        b)工作项初始化:INIT_WORK(&async_event_work, nvme_async_event_work);

        4、向工作队列添加工作项:

                        queue_work(nvme_wq, &async_event_work);它的调用时机由调度器确定;

                        另一个函数是:queue_work_delayed(),它确保在延期工作执行之前,至少经过dalay指定的一段时间;

        有另外几个常用的函数:

                        flush_work(&async_event_work); //等待工作执行完成

                        flush_workqueue(wq); //参数是工作队列,等待队列上的所以工作都完成

以上是我们自定义了工作队列,其实系统自带了标准的工作队列,我们只需要将新的工作项添加到该队列就行了,使用如下两个函数:

schedule_work(&ctrl->failfast_work);

or              

schedule_delayed_work(&ctrl->failfast_work, time);

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值