linux INIT_WORK 创建工作队列

本文详细介绍了 Linux 2.6 内核中的工作队列机制,包括如何使用系统共享的工作队列及如何创建自定义工作队列。探讨了工作队列与 tasklet 的区别,以及在不同场景下的应用方式。

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

Linux 2.6内核使用了不少工作队列来处理任务,他在使用上和 tasklet最大的不同是工作队列的函数可以使用休眠,而tasklet的函数是不允许使用休眠的。

工作队列的使用又分两种情况,一种是利用系统共享的工作队列来添加自己的工作,这种情况处理函数不能消耗太多时间,这样会影响共享队列中其他任务的处理;另外一种是创建自己的工作队列并添加工作。

(一)利用系统共享的工作队列添加工作

Ø        第一步:声明或编写一个工作处理函数

void my_func();

Ø        第二步:创建一个工作结构体变量,并将处理函数和参数的入口地址赋给这个工作结构体变量

DECLARE_WORK(my_work,my_func,&data); //编译时创建名为my_work的结构体变量并把函数入口地址和参数地址赋给它;

如果不想要在编译时就用DECLARE_WORK()创建并初始化工作结构体变量,也可以在程序运行时再用INIT_WORK()创建

struct work_struct my_work; //创建一个名为my_work的结构体变量,创建后才能使用INIT_WORK()

INIT_WORK(&my_work,my_func,&data); //初始化已经创建的my_work,其实就是往这个结构体变量中添加处理函数的入口地址和data的地址,通常在驱动的open函数中完成

Ø        第三步:将工作结构体变量添加入系统的共享工作队列

schedule_work(&my_work); //添加入队列的工作完成后会自动从队列中删除

schedule_delayed_work(&my_work,tick); //延时tick个滴答后再提交工作

(二)创建自己的工作队列来添加工作

Ø        第一步:声明工作处理函数和一个指向工作队列的指针

void my_func();

struct workqueue_struct *p_queue;

Ø        第二步:创建自己的工作队列和工作结构体变量(通常在open函数中完成)

p_queue=create_workqueue("my_queue"); //创建一个名为my_queue的工作队列并把工作队列的入口地址赋给声明的指针

struct work_struct my_work;

INIT_WORK(&my_work, my_func, &data); //创建一个工作结构体变量并初始化,和第一种情况的方法一样

Ø        第三步:将工作添加入自己创建的工作队列等待执行

queue_work(p_queue, &my_work);

//作用与schedule_work()类似,不同的是将工作添加入p_queue指针指向的工作队列而不是系统共享的工作队列

Ø        第四步:删除自己的工作队列

destroy_workqueue(p_queue); //一般是在close函数中删除
在T2上创建队列 ,延时几个MS才响应,这是什么概念!还有解决这问题!!

 

1.INIT_WORK(struct work_struct *work, void (*function)(void *), void *data)
上面一句只是定义了work和work对应的操作。
要是在实际使用的时候还是需要你去在适当的条件下激活这个work。只有激活了这个work,
这个work才有运行的机会。这个激活操作接口是shudule_work或是queue_work。
这两个接口之后只是说这个work有了运行的机会,但是具体到什么时候运行,那要看你用哪个接口激活的。
如果是shudule_work的话,系统中有个events内核线程,这个线程会处理你用shudule_work接口激活
的所有work。如果是queue_work的话,一般这种情况都是自己创建了一个单独的处理线程,这样将
你激活的work和这个线程联系起来。至于什么时候运行,那就是events或是你定义的特定线程运行的时候。

2.至于你提到的为什么要用到work。这个的话,我个人的理解是:一般用在对耗时处理上。比如,
当中断发生的时候,你可以在中断上下文中完成激活操作,让那些耗时的操作在work中完成。

 

在2.6.22版本中,INIT_WORK已经做了大幅度的修改。INIT_WORK现在使用2个参数,分别是链表和任务,去掉了数据。这时我们的任务func以_work作为参数。我们需要将我们的work结构加入到我们的data结构中,然后使用container_of这个函数来求出我们的data的指针。

 

 

<think>好的,用户想了解Linux内核中的INIT_WORK宏的定义和用法。首先,我需要回忆INIT_WORK在内核中的作用。记得它和工作队列有关,用来初始化工作结构,将工作项和对应的处理函数绑定。 接下来,用户可能是在开发内核模块时需要用到工作队列,所以需要知道如何正确使用INIT_WORK。要解释清楚这个宏的参数,比如struct work_struct指针和函数指针,以及可能的上下文传递。 然后,需要考虑用户的使用场景,比如是否涉及延迟工作,是否需要区分INIT_WORKINIT_DELAYED_WORK。引用中的资料提到这两对函数,应该指出它们的区别,帮助用户避免混淆。 另外,用户可能对工作队列的整体机制不太熟悉,需要简要说明工作队列的作用,以及schedule_work的使用方法。结合引用中的例子,比如引用[2]提到的接口对,说明初始化后如何调度工作。 还要注意代码示例的正确性,确保语法正确,比如使用正确的宏和函数调用。可能需要提供一个简单的内核模块示例,展示如何定义工作结构、初始化、编写处理函数并调度。 同时,用户的问题可能涉及开发文档,需要确认内核版本或文档来源,但引用中的信息已经足够回答基本用法。需要提醒用户参考内核源码或官方文档以获取最新信息。 最后,生成相关问题时,要考虑用户可能的后续疑问,比如错误处理、并发问题、替代方案等,帮助用户全面理解INIT_WORK的应用场景和注意事项。</think>### INIT_WORK 宏的解析 #### 1. 定义与作用 `INIT_WORK` 是 Linux 内核提供的宏,用于初始化工作队列中的工作结构(`struct work_struct`)。它将工作项与具体的处理函数绑定,定义在 `include/linux/workqueue.h` 中[^1][^2]。其标准语法为: $$INIT_WORK(_work, _func)$$ 其中: - `_work`:指向工作结构的指针 - `_func`:工作处理函数的函数指针 #### 2. 使用场景 主要应用于需要异步执行任务的场景: 1. **中断上下文**:当需要将耗时操作转移到进程上下文执行时 2. **模块初始化**:注册设备驱动时初始化后台任务 3. **延迟处理**:配合 `schedule_work()` 实现任务调度[^2] #### 3. 代码示例 ```c #include <linux/workqueue.h> // 定义工作结构和工作函数 static struct work_struct my_work; void work_handler(struct work_struct *work) { printk("Work executed in process context\n"); } // 模块初始化时调用 static int __init my_module_init(void) { INIT_WORK(&my_work, work_handler); // 绑定工作项与处理函数 schedule_work(&my_work); // 将工作项加入系统默认队列 return 0; } ``` #### 4. 关键特性 | 特性 | 说明 | |---------------------|-----------------------------| | 执行上下文 | 进程上下文(可休眠)[^1] | | 调度方式 | 通过 `schedule_work()` 提交 | | 与 `INIT_DELAYED_WORK` 区别 | 不支持延迟执行[^3] | #### 5. 开发注意事项 - 工作处理函数**不可访问用户空间** - 需确保工作结构在有效作用域内 - 高频率任务建议使用专用工作队列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值