顶半部低半部机制

本文探讨了Linux内核对中断函数的短时处理要求,针对无法满足快速响应的硬件中断,介绍了顶半部和低半部机制。顶半部用于紧急快速处理,低半部则通过Tasklet处理耗时任务。此外,文章详细讲解了Tasklet和工作队列的区别,以及如何使用它们优化按键驱动和耗时操作。

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

1.linux内核对中断函数的要求
切记:linux内核要求中断函数处理时间越短越好,更不能进行休眠操作
问:linux内核有些硬件的中断处理函数是无法满足这个要求的,linux内核的这个要求如果无法满足,会影响linux
内核的并发和相应能力,对于这种情况linux内核是怎么处理的?
答:如果有中断函数长时间占用占用cpu资源的情况,可以使用linux内核的顶半部和低半部机制来进行优化
中断编程的顶半部和低半部的本质目的就是解决中断函数长时间占用cpu资源引起影响系统的并发和响应能力

2.linux内核顶半部和低半部的特点
顶半部做原先中断处理函数中比较紧急,耗时较短的内容
一旦硬件中断出发,cpu首先执行顶半部,执行时间非常快,会立即释放cpu资源给其他任务使用,cpu
在执行期间不允许发生cpu资源的切换,顶半部的本质就是中断处理函数,只是里面做的内容比较快

低半部做原先中断处理函数中比较耗时,不紧急的任务,cpu会在适当的时候去执行低半部(当cpu执行低半部的时候,低半部
的优先级是最高的,但是cpu在执行期间,如果来了一个高优先级的任务,势必会抢走低半部的cpu资源,当高优先级的任务执行完,还会
把cpu资源还给低半部,低半部继续执行,低半部的本质就是延后执行)

3.低半部实现机制之tasklet
tasklet特点:tasklet本身是基于软中断,优先级高于进程而低于硬中断
所以tasklet对应的延后处理函数不能休眠,tasklet对应的延后处理函数处理比较耗时,不紧急的内容

linux内核描述tasklet的数据结构
struct tasklet_struct{
	struct tasklet_struct *tasklet;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long data);//用到的是这两个数据,上面的用不到
	unsigned long data
};

成员说明:
func:tasklet的延后处理函数,做原先中断处理函数中中不紧急的实现,由于基于软中断的实现,所以里面不能进行休眠操作
形参data保存传递过来的参数
data:给tasklet延后处理函数传递的参数

编程步骤:
1.定义初始化一个tasklet对象

int data = 0x55;
	DECLARE_TASKLET(btn_tasklet,//对象名
					btn_tasklet_func,//延后处理函数
					(unsigned long)&data//传递参数);

2.编写tasklet延后处理函数

void btn_tasklet_func(unsigned long data)
{
	
}

3.在顶半部处理函数中向内核登记(而不是调用),一旦登记完成,内核会在适当的时候去调用tasklet延后处理函数
登记函数:
tasklet_schedule(&btn_tasklet);

案例:利用tasklet优化按键驱动
原先的按键处理函数中,其实速度已经很快,但还有进一步优化的空间,printk函数操作的是硬件uart,而uart是一个低速设备
,当cpu执行printk函数时,必定会拉长cpu执行时间,多少会影响系统系统的并发和相应
切记:printk虽然能打印调试信息,但是用多了没好处,耗费cpu资源

4.底半部机制工作队列
工作队列特点:基于进程实现
工作队列诞生的本质就是解决tasklet延后处理函数不能进行休眠操作的问题
因为有些场合需要在延后处理的过程中进行休眠操作,对于这种情况必须适应工作队列,所以工作队列基于进程实现,所以工作队列的延后处理函数
可以进行休眠操作,但是它的优先级低于软中断,硬中断
linux内核描述工作队列的数据结构:
struct work_struct{
work_func_t func;

};
func:工作队列的延后处理函数,里面可进行休眠操作
配套函数:
INIT_WORK(&工作队列对象,工作队列的延后处理函数);
//向内核登记工作队列的延后处理函数,一旦登记完成,将来内核在适当的时候调用其延后处理函数
schedule_work(&工作队列对象);

编程 步骤:
1.定义初始化工作队列对象
struct work_struct btn_work;
INIT_WORK(&btn_work,btn_work_func);

2.编写工作队列延后处理函数
此函数可以进行休眠操作
void btn_work_func(struct work_struct *work)
{
不紧急耗时较长的内容
}

3.向内核登记工作队列的延后处理函数,一旦登记完成,内核在适当的时候调用延后处理函数
schedule_work(&btn_work);

总结:
1.如果延后执行的函数中,没有休眠操作,两者都可以
2.如果需要休眠,选用工作队列
3.如果无需休眠,且考虑效率的话,用tasklet,因为tasklet基于软中断,优先级高于基于进程的工作队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值