中断的下半部处理机制(2)工作队列

工作队列是Linux内核中一种将任务推后执行的技术,它使用内核线程在进程上下文中执行任务,允许任务睡眠。本文详细介绍了工作队列的结构、如何创建工作、调度工作以及其在进程上下文中的执行特性,并提供了一个简单的应用示例。

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

工作队列是另一种将工作推后执行的形式,他和前面讨论的所有其他形式都有所不同。工作队列可以吧工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被调用甚至是睡眠。

那么什么情况下使用工作队列,什么情况下使用小任务?如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后的任务不需要睡眠,那么就选择小任务。另外,如果需要一个用一个可以重新调度的实体来执行下半部的处理,也应该使用工作队列。它是唯一一个能在进程上下文运行下半部实现的机制,也只有它才可以睡眠。如果不需要一个内核线程来推后执行工作,就可以考虑使用小任务。


1.工作,工作队列和工作者线程

如前所述,我们把推后执行的任务叫做工作,描述它的数据结构为work_struct,这些工作以队列结构组织成工作队列,其数据结构为workqueue_struct,而工作者线程就是负责执行工作队列中的工作。系统默认的工作者线程为events,自己也可以创建自己的工作者线程。


2.表示工作的数据结构

在linux/workqueue.h中定义了work_struct结构:

struct work_struct {

    unsigned long pending;    //这个工作正在等待处理么

    struct list_head entry;         //工作的链表

    void (*func)(void *);              //要执行的函数

    void *data;                             //传递给函数的参数

    void *wq_data;                      //内部使用

    struct timer_list timer;          //延迟的工作队列所用到的定时器

};


这些结构被链接成链表。当一个工作者线程被唤醒时,它会执行它的链表上的所有工作。工作执行完毕,它就将相应的work_struct 对象从链表上移去。当链表上不再有对象的时候,他就会继续睡眠。


3.创建推迟后的工作

要使用工作队列,首先要做的是创建一些需要退后完成的工作。可以通过DECLARE_WORK在编译时静态地创建该结构:

DECLARE_WORK(name, void (* func)(void *), void *data);

这样就静态的创建一个名为name,待执行函数为func,参数为data的work_struct结构。

同样也可以使用指针创建一个工作。

INIT_WORK(struct work_struct *work, void (*func)(void *), void *data);

这将动态的初始化一个由work指向的工作。


4.工作队列中待执行的函数

工作队列待执行的函数的原型是:

void work_handler(voif *data)

这个函数由一个工作者线程和执行,因此,函数运行在进程上下文中。默认情况下,允许响应中断,并不持有任何锁。如果需要,函数可以睡眠。需要注意的是,尽管该函数运行在进程上下文中,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射。通常在系统调用时,内核代表用户空间的进程运行,此时它才能访问用户空间,也只有在此时刻它才映射用户空间的内存。


5.对工作进行调度

已经被创建,我们可以调度它。想要把给定工作的待处理函数提交给缺省的events工作线程,只需调用:

schedule_work(&work);

工作马上就被调度了,一旦在其所在的处理器上的工作者线程被唤醒,他就被执行。有时候并不希望工作马上就被执行,而是希望它经过一段延迟以后在执行,这种情况下,可以调度他在指定时间上执行:

schedule_delayed_work(&work,delay);

这时,&work指向的work_struct直到delay指定的时钟节拍用完才会执行。


6.工作队列的简单应用

#include<linux/module.h>
#include<linux/init.h>
#include<linux/workqueue.h>

static struct workqueue_struct *queue = NULL;
static struct work_struct work;

static void work_handler(struct work_struct *data)
{
    printk(KERN_ALERT"work handler function.\n");
}

static int __init test_init(void)
{
    queue = create_singlethread_workqueue("helloworld");
    if(!queue)
        goto err;
    INIT_WORK(&work, work_handler);
    schedule_work(&work);
    return 0;

    err:
        return -1;
}

static void __exit test_exit(void)
{
    destroy_workqueue(queue);
    printk("destory-workqueue\n");
}

MODULE_LICENSE("GPL");:
module_init(test_init);
module_exit(test_exit);


用insmod加载模块后dmesg:

此时已执行了该工作上的函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值