软中断,tasklet和工作队列的区别与联系

本文介绍了Linux内核中处理中断的下半部机制,包括软中断、tasklet和工作队列的特点与区别。软中断适用于特定子系统如网络和SCSI,tasklet用于大多数情况,而工作队列则允许执行阻塞操作。

转载地址:http://sunxinrui.blog.sohu.com/120659923.html


为了让中断处理运行的快,同时要完成相应的全部工作。根据具体的内容将中断分为两个部分:上半部分(中断处理程序)和下半部分(推后处理程序)。上半部分需要立即执行,并且有严格的时间限制,这些工作是在所有中断被禁止的情况下完成的,剩余部分工作推迟到下半部分。

下半部分的任务就是执行与中断处理密切相关但中断处理程序本身不执行的工作。在Linux2.6的内核中存在三种不同形式的下半部实现机制:软中断,tasklet和工作队列。
下面将比较三种机制的差别与联系。
软中断: 1、软中断是在编译期间静态分配的。
         2、最多可以有32个软中断。
         3、软中断不会抢占另外一个软中断,唯一可以抢占软中断的是中断处理程序。
         4、可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),
            因此也需要使用自旋锁来保护其数据结构。
         5、目前只有两个子系直接使用软中断:网络和SCSI。
         6、执行时间有:从硬件中断代码返回时、在ksoftirqd内核线程中和某些显示检查并执行软中断的代码中。
tasklet: 1、tasklet是使用两类软中断实现的:HI_SOFTIRQ和TASKLET_SOFTIRQ。
          2、可以动态增加减少,没有数量限制。
          3、同一类tasklet不能并发执行。
          4、不同类型可以并发执行。
          5、大部分情况使用tasklet。
工作队列: 1、由内核线程去执行,换句话说总在进程上下文执行。
          2、可以睡眠,阻塞。
<think>我们正在讨论Linux内核中tasklet工作队列(workqueue)的创建方法。根据提供的引用材料,我们可以总结如下:1.**tasklet**:-是一种软中断(softirq)机制,运行在中断上下文中,不能睡眠。-创建方法:使用`tasklet_init()`函数初始化,然后使用`tasklet_schedule()`调度执行。-销毁方法:在模块卸载时使用`tasklet_kill()`。2.**工作队列(workqueue)**:-将工作推迟到内核线程中执行,运行在进程上下文中,可以睡眠。-创建方法:可以使用系统默认的工作队列(如`eventd_wq`)或者自己创建(`create_workqueue`)。-调度方法:使用`schedule_work()`或`queue_work()`将工作添加到队列。下面我将详细说明两者的创建步骤示例代码。###1.Tasklet的创建使用####步骤:1.**定义tasklet结构体**:`structtasklet_struct`2.**初始化tasklet**:使用`tasklet_init()`函数,指定处理函数参数。3.**调度tasklet**:使用`tasklet_schedule()`将tasklet加入软中断队列等待执行。4.**销毁tasklet**:在模块退出时使用`tasklet_kill()`。####示例代码(基于引用[2]):```c#include<linux/init.h>#include<linux/module.h>#include<linux/interrupt.h>staticstructtasklet_structmy_tasklet;//Tasklet处理函数staticvoidtasklet_handler(unsignedlongdata){printk(KERN_INFO"Taskletisrunning\n");}staticint__initmy_module_init(void){//初始化tasklet,关联处理函数tasklet_init(&my_tasklet,tasklet_handler,0);//调度tasklettasklet_schedule(&my_tasklet);return0;}staticvoid__exitmy_module_exit(void){//销毁tasklettasklet_kill(&my_tasklet);printk(KERN_INFO"Moduleexit\n");}module_init(my_module_init);module_exit(my_module_exit);MODULE_LICENSE("GPL");```###2.Workqueue的创建使用####两种方式:-**使用系统默认工作队列**:无需自己创建队列,直接定义`work_struct`并使用`schedule_work()`调度。-**创建自定义工作队列**:使用`create_workqueue()`创建,然后使用`queue_work()`调度。####步骤(自定义工作队列):1.**创建工作队列**:`create_workqueue(name)`2.**定义工作结构体**:`structwork_struct`3.**初始化工作**:`INIT_WORK(work,work_func)`4.**调度工作**:`queue_work(workqueue,work)`5.**销毁工作队列**:使用`destroy_workqueue()`####示例代码(自定义工作队列):```c#include<linux/init.h>#include<linux/module.h>#include<linux/workqueue.h>staticstructworkqueue_struct*my_wq;staticstructwork_structmy_work;//工作处理函数staticvoidwork_handler(structwork_struct*work){printk(KERN_INFO"Workqueuehandlerisrunning\n");}staticint__initmy_module_init(void){//创建工作队列my_wq=create_workqueue("my_workqueue");if(!my_wq)return-ENOMEM;//初始化工作,关联处理函数INIT_WORK(&my_work,work_handler);//调度工作queue_work(my_wq,&my_work);return0;}staticvoid__exitmy_module_exit(void){//销毁工作队列destroy_workqueue(my_wq);printk(KERN_INFO"Moduleexit\n");}module_init(my_module_init);module_exit(my_module_exit);MODULE_LICENSE("GPL");```###关键区别总结|特性|Tasklet|Workqueue||---------------------|----------------------------------|----------------------------||执行上下文|中断上下文(不可睡眠)|进程上下文(可睡眠)||并发性|同类型tasklet不能并发执行|可并发执行(多线程)||创建方式|`tasklet_init`+`tasklet_schedule`|`create_workqueue`+`INIT_WORK`+`queue_work`||适用场景|短时间、不可睡眠的任务|可能睡眠或长时间的任务|###注意事项1.**Tasklet安全性**:同一tasklet不会同时在多个CPU上运行,但不同tasklet可以并行[^1]。2.**Workqueue资源**:自定义工作队列会创建独立的内核线程,消耗更多资源[^3]。3.**默认工作队列**:使用`schedule_work(work)`会使用系统共享的工作队列(如`system_wq`),避免资源浪费[^4]。§§相关问题§§1.Linux内核中软中断(softirq)tasklet有什么关系?2.工作队列(workqueue)内核线程(kthread)有何区别联系?3.如何选择使用tasklet还是workqueue?4.工作队列中的工作是如何被调度的?</think>### Linux内核中TaskletWorkqueue创建方法详解 #### 一、Tasklet创建方法 TaskletLinux内核中用于中断下半处理的轻量级机制,运行在软中断上下文。 **创建步骤:** 1. **声明tasklet结构体** ```c static struct tasklet_struct my_tasklet; ``` 2. **定义处理函数** ```c static void tasklet_handler(unsigned long data) { printk(KERN_INFO "Tasklet executed\n"); // 处理逻辑 } ``` 3. **初始化tasklet** ```c tasklet_init(&my_tasklet, tasklet_handler, 0); // 0为传入参数 ``` 4. **调度tasklet** ```c tasklet_schedule(&my_tasklet); // 加入执行队列 ``` 5. **销毁tasklet**(模块退出时) ```c tasklet_kill(&my_tasklet); // 确保安全终止[^2] ``` **特性:** - 原子性:同类型tasklet不会并发执行 - 不可睡眠:运行在中断上下文 - 低延迟:适合实时性要求高的场景[^1] #### 二、Workqueue创建方法 Workqueue将工作推迟到内核线程执行,运行在进程上下文,可处理复杂操作。 **两种创建方式:** 1. **使用系统默认工作队列**(推荐) ```c static struct work_struct my_work; // 定义工作处理函数 void work_handler(struct work_struct *work) { printk(KERN_INFO "Work executed in kernel thread\n"); } // 初始化调度 INIT_WORK(&my_work, work_handler); schedule_work(&my_work); // 加入系统队列[^4] ``` 2. **创建自定义工作队列** ```c struct workqueue_struct *custom_wq = create_workqueue("my_wq"); static struct work_struct custom_work; INIT_WORK(&custom_work, work_handler); // 提交到自定义队列 queue_work(custom_wq, &custom_work); // 销毁队列(模块退出时) destroy_workqueue(custom_wq);[^3] ``` **关键特性对比:** | 特性 | Tasklet | Workqueue | |---------------------|-----------------------------|----------------------------| | 执行上下文 | 中断上下文(不可睡眠) | 进程上下文(可睡眠) | | 并发性 | 同类型串行执行 | 可并行执行 | | 适用场景 | 简单快速操作 | 复杂/可能阻塞的操作 | | 资源消耗 | 低 | 较高(需内核线程) | | 超时处理 | 不支持 | 支持延迟工作(delayed_work) | #### 三、使用场景选择 1. **选择Tasklet当:** - 需要极低延迟(如网络包处理) - 操作简单且不可阻塞 - 避免线程调度开销[^1] 2. **选择Workqueue当:** - 需要执行可能阻塞的操作(如I/O) - 需要睡眠或等待资源 - 复杂处理需要进程上下文[^3] #### 四、最佳实践 1. **内存管理:** ```c // Tasklet共享数据需原子操作 atomic_t shared_data = ATOMIC_INIT(0); // Workqueue可使用标准锁机制 DEFINE_SPINLOCK(my_lock); ``` 2. **错误处理:** ```c // Workqueue创建需检查 if (!custom_wq) { printk(KERN_ERR "Workqueue creation failed\n"); return -ENOMEM; } ``` 3. **性能优化:** - 高频任务用`tasklet_hi_schedule()`提高优先级 - CPU密集型工作用`create_singlethread_workqueue()`
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值