linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】
转自:http://blog.chinaunix.net/uid-20768928-id-5077401.html
在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方法来进行实现此功能。先讲两个小故事来描述一下,遇到的问题。也是因为自己对底半部机制理解得不透彻。这些故事的前提都是在串口中断中,一定条件后去完成某件事情,但时间上不能超过5ms。
故事一,最开始想到的是用workqueue。印象中workqueue 就是用来做这种事的,并且还记得可以延时一段时间再来做。
点击(此处)折叠或打开
- INIT_WORK(&my_wq,(void (*) (void*))my_wq_func);
- schedule_work(&my_wq);
- //schedule_delayed_work(&my_wq,delay);
最终实现的结果是,my_wq_func 的执行是在中断响应后,但响应时间不确定。短的时候是1毫秒以内,长得的时候出现过几十个毫秒。这样就达不到我们的要求。为什么出现这种时间不确定的问题呢?等故事讲完再一起分析。schedule_delayed_work 延时执行的时间为最小一个jiffies,显然不能用在我们这种情况,我们要求小于5ms。
点击(此处)折叠或打开
- tasklet_init(&my_task0,my_wq_func,(unsigned long) my_wq_arg);
- tasklet_schedule(&my_task0);
- tasklet_hi_schedule(&my_task0);
最终这种方法实现了。但过程也是相当曲折。tasklet_schedule时效性可以达到,hi_schedule 更是完美,感觉会牺牲系统性能。那么过程曲折在哪呢?刚开始以为搞好了,回家睡大觉,等我九点半到家,同事打电话说不行,出问题了。单个串口没有问题,多个串口同时用的时候,前面打开的串口对应的rs485 都不能正常使用。GPIO拉高后,就不低。而my_wq_func就是实现GPIO拉低的动作。最后的原因是my_wq_func被多次调用,而其只响应最后一次。这个地方还得感谢这位老兄,http://blog.csdn.net/goodluckwhh/article/details/9003353 。tasklet 是一个特殊的函数, 它在软中断上下文被调度。它可能被调度运行多次,但是tasklet调度不累积,也就是即使在tasklet被执行之前请求了多次来执行该tasklet,它也只运行一次。不会有同一个tasklet的多个实例同时运行。但是tasklet可以与SMP系统上的其他tasklet并行运行。因此, 如果多个tasklet会使用相同的资源, 它们必须采取某类加锁来避免彼此冲突。除非tasklet重新激活自己,否则每次tasklet激活只会运行一次。最后的解决方法就是将my_wq_func一个函数可以实现的内容,复制成了四个函数,问题就解决了。
故事讲完了,这时候该来分析分析理论上的底半部机制。前面的曲折,主要是因为自己对底半部机制的一知半解。这里来着重分析一下任务队列,工作队列的区别,同时也COPY一些别人对软中断的理解,以备后续查看
工作队列,任务队列,软中断
工作队列:Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化。可以参考http://blog.csdn.net/angle_birds/article/details/8448070
点击(此处)折叠或打开
- DECLARE_WORK(struct work_struct , work_func_t func);
- INIT_WORK(struct work_struct *work, work_func_t func);
- INIT_DELAYED_WORK(struct delayed_work *work, work_func_t func);
- int schedule_work(struct work_struct *work);
- int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
- int schedule_delayed_work_on(struct delayed_work *work, unsigned long delay);
- struct workqueue_struct *create_workqueue(const char *name);
- int queue_work(struct workqueue_struct *wq, struct work_struct *work);
- int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work,
- unsigned long delay);
- void flush_scheduled_work(void);
- void flush_workqueue(struct workqueue_struct *wq);
- int cancel_delayed_work(struct delayed_work *work);
- void destroy_workqueue(struct workqueue_struct *wq);
任务队列:是一个由系统决定的安全时刻在软件中断上下文被调度运行的特殊函数。注意tasklet只会运行一次,即使在激活tasklet的运行之前重复请求该tasklet的运行也是这样。但是他可以与其他tasklet并行的运行在对称多处理器(SMP)系统上。
点击(此处)折叠或打开
- DECLARE_TASKLET(name, func, data);
- void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
- void tasklet_schedule(struct tasklet_struct *t);
- void tasklet_hi_schedule(struct tasklet_struct *t);
- void tasklet_disable(struct tasklet_struct *t);
- void tasklet_disable_nosync(struct tasklet_struct *t);
- void tasklet_enable(struct tasklet_struct *t);
- void tasklet_kill(struct tasklet_struct *t);
软中断:利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。很多情况下,软中断和"信号"有些类似,同时,软中断又是和硬中断相对应的,"硬中断是外部设备对CPU的中断","软中断通常是硬中断服务程序对内核的中断","信号则是由内核(或其他进程)对某个进程的中断"
点击(此处)折叠或打开
- void open_softirq(int nr, void (*action)(struct softirq_action *));
- void raise_softirq(unsigned int nr);
- asmlinkage void do_softirq(void) ;
他们之间的差异做了一个对比
通过上面的表格也就能明白,这三种分别适应的场合。以下原则
1,需要睡眠,阻塞的,只能用工作队列。
2,短时间内中断数量很多的,任务队列,软中断会更好。例如网络。
3,对性能要求很高的话,软中断最好。
4,使用任务队列时,应该注意同一个任务被多次调用,同一个函数被多个任务队列注意。
5,软中断要注意SMP,函数的重入。
linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】的更多相关文章
- Linux中断底半部机制
参考: Linux下半部处理之软中断 linux中断底半部机制 <深入理解Linux内核>软中断/tasklet/工作队列 软中断和tasklet介绍 详解操作系统中断 Linux内核:中 ...
- linux底半部机制在视频采集驱动中的应用
最近在做一个arm+linux平台的视频驱动.本来这个驱动应该是做板子的第三方提供的,结果对方软件实力很差,自己做不了这个东西,外包给了一个暑期兼职的在读博士.学生嘛,只做过实验,没做过产品,给出的东 ...
- linux中断的下半部机制
一.中断处理为什么要下半部?Linux在中断处理中间中断处理分了上半部和下半部,目的就是提高系统的响应能力和并发能力.通俗一点来讲:当一个中断产生,调用该中断对应的处理程序(上半部)然后告诉系统,对应 ...
- linux中断编程
本文档只介绍中断编程所需的函数及应用,中断完整处理流程应参考文档<linux中断处理流程>,可参考文档<linux内核对中断的处理方式>对中断初步了解. 本文档基于3.14内核 ...
- Linux内核中断顶半部和底半部的理解
文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...
- Linux设备驱动程序:中断处理之顶半部和底半部
http://blog.csdn.net/yuesichiu/article/details/8286469 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可 ...
- 底半部之工作队列和tasklet,内核定时器。
1.软中断机制 不能以模块形式出现 使用起来不够灵活2.tasklet 核心数据结构 struct tasklet_struct { function ...
- linux中断处理-顶半部(top half)和底半部(bottom half) -转
原文:http://rensanshi.blog.163.com/blog/static/21395510820136282224877/ 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率 ...
- linux中断
[一].中断底半部 1. 软中断 --->>> 执行在中断上下文 --->>> 会被中断打断,不会被软中断或进程打断 --->>> ...
随机推荐
- itest(爱测试) 4.1.5 发布,开源BUG 跟踪管理 & 敏捷测试管理软件
v4.1.5下载地址 :itest下载 itest 简介:查看简介 itest 开源敏捷测试管理,testOps 践行者.可按测试包分配测试用例执行,也可建测试迭代(含任务,测试包,BUG)来组织测试 ...
- zz《分布式服务架构 原理、设计与实战》综合
这书以分布式微服务系统为主线,讲解了微服务架构设计.分布式一致性.性能优化等内容,并介绍了与微服务系统紧密联系的日志系统.全局调用链.容器化等. 还是一样,每一章摘抄一些自己觉得有用的内容,归纳整理, ...
- 剑指Offer-14.链表中倒数第k个结点(C++/Java)
题目: 输入一个链表,输出该链表中倒数第k个结点. 分析: 第一个解法,我们可以先遍历一遍链表,计算下节点的总数n,然后再从头结点查n-k个节点,即是倒数第k个节点. 第二个解法,便是使用双指针,两个 ...
- 【2019.8.9 慈溪模拟赛 T1】数论(a)(打表找规律)
莫比乌斯反演 血亏! 比赛时看到这题先写了个莫比乌斯反演,然后手造了几组数据和暴力对拍的时候发现,居然答案就是\(nm\)... 吐槽数据范围太小... 下面给上出题人对此题的解释: 原式的物理意义, ...
- Paper | UNet++: A Nested U-Net Architecture for Medical Image Segmentation
目录 1. 故事 2. UNet++ 3. 实验 3.1 设置 作者的解读,讲得非常好非常推荐:https://zhuanlan.zhihu.com/p/44958351 这篇文章提出的嵌套U-Net ...
- P1验证性内容
#include<stdio.h> int main() { printf("201983270555"); return 0; } #include<stdio ...
- sqlplus简单使用
登录 C:\Users\inmeditation>sqlplus 请输入用户名: scott 输入口令: 查看当前行长 SQL> show linesize; linesize 80 查看 ...
- 明解JAVA 第一章答案
练习1-1 无法运行 练习1-2 package candle1220; class Nightwatch{ public static void main(String[] args) { Syst ...
- javascript模块化编程的cmd规范(sea.js)
CMD(Common Module Definition,通用模块定义)是一种模块定义规范,规范中明确了模块的基本书写格式和基本交互规则.SeaJS就是遵循的这个规范. define函数 在CMD规范 ...
- 基于OceanStor Dorado V3存储之精简高效 Smart 系列特性
基于OceanStor Dorado V3存储之精简高效 Smart 系列特性 1.1 在线重删 1.2 在线压缩 1.3 智能精简配置 1.4 智能服务质量控制 1.5 异构虚拟化 1.6 ...