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);
故事讲完了,这时候该来分析分析理论上的底半部机制。前面的曲折,主要是因为自己对底半部机制的一知半解。这里来着重分析一下任务队列,工作队列的区别,同时也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,函数的重入。