Linux设备驱动程序 之 工作队列
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Linux设备驱动程序 之 工作队列,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3168字,纯文字阅读大概需要5分钟。
内容图文
工作队列可以把工作推后,交给一个内核线程去执行–这个下半部分总是会在进程上下文中执行;通过工作队列执行的代码占尽进程上下文的优势;最重要的是工作队列允许重新调度甚至睡眠;
在工作队列和软中断/tasklet中做出选择很容易;如果推后执行的任务需要睡眠,那么就选择工作队列;如果推后执行的任务不需要睡眠,那么就选择软中断或者tasklet;
如果需要用一个可以重新调度的实体来执行下半部处理,那么应该使用工作队列;它是唯一能在进程上下文中运行的下半部机制,也只有它才可以睡眠;这意味着如果需要获取大量的内存,或者在需要获取信号量时,或者需要执行阻塞式IO操作时,它会非常有用;如果不需要一个内核线程来推后执行工作,那么考虑使用tasklet;
创建推后的工作
可以通过DECLARE_WORK在编译时静态的创建work_struct结构实例并初始化:
1 #define DECLARE_WORK(n, f) 2struct work_struct n = __WORK_INITIALIZER(n, f) 34#define DECLARE_DELAYED_WORK(n, f) 5struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, 0) 67#define DECLARE_DEFERRABLE_WORK(n, f) 8struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, TIMER_DEFERRABLE)
或者在运行时动态的创建一个work_struct实例,然后使用下面函数进行初始化:
1 #define INIT_WORK(_work, _func) 2 __INIT_WORK((_work), (_func), 0) 3 4#define INIT_WORK_ONSTACK(_work, _func) 5 __INIT_WORK((_work), (_func), 1) 6 7#define INIT_DELAYED_WORK(_work, _func) 8 __INIT_DELAYED_WORK(_work, _func, 0) 910#define INIT_DELAYED_WORK_ONSTACK(_work, _func) 11 __INIT_DELAYED_WORK_ONSTACK(_work, _func, 0)
工作队列处理函数
工作队列处理函数的原型是:
1 typedef void (*work_func_t)(struct work_struct *work);
这个函数会由一个工作者线程执行,因此,函数会运行在进程上下文中;默认情况下,允许响应中断,并不持有任何锁;如果需要,函数可以睡眠;
需要注意的是,尽管操作处理函数运行在进程上下文,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射;通常在发送系统调用时,内核会代表用户空间进程运行,也只有此时它才会映射用户空间的内存;
调度工作(缺省工作队列)
如果要把给定工作的处理交给缺省的工作线程,则需要调用:
1 bool schedule_work(struct work_struct *work)
work马上会被调度,一旦其所在的处理器上的工作线程被唤醒,它就会被执行;
如果不希望马上被执行,而是希望它经过一段时间的延迟后才执行,则需要下面函数,可以在指定时间之后执行:
1 bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay)
这时,dwork会在delay指定的始终节拍用完之后才会执行;
刷新操作
排入队列的工作会在工作者线程下一次被唤醒时执行;有时,在继续下一步工作之前,必须保证一些操作已经执行完毕了;这一点对模块来说就很重要,在卸载之前,它就有可能需要调用下面的函数;而在内核的其他部分,为了防止竞争条件的出现,也可能需要确保不再有待处理的工作;
为了,内核准备了用于刷新指定工作队列的函数:
1 bool flush_work(struct work_struct *work); 23bool flush_delayed_work(struct delayed_work *dwork);
函数会一直等待,直到队列中的所有对象都被执行以后才返回;在等待所有待处理的工作执行的时候,该函数会进入休眠状态,所以只能在进程上下文中使用;
内核也提供了取消执行工作的函数:
1 bool cancel_work(struct work_struct *work); 2bool cancel_work_sync(struct work_struct *work); 34bool cancel_delayed_work(struct delayed_work *dwork); 5bool cancel_delayed_work_sync(struct delayed_work *dwork);
创建新的工作队列
如果缺省队列不能满足需求,则应该创建一个新的工作队列和与之对应的工作者线程;由于这么做会在每个处理器上都创建一个工作者线程,所以只有在你明确了必须要靠自己一套线程来提高性能的情况下,再创建自己的队列;
创建一个新的任务队列和与之相关的工作者线程,需要使用下面函数,name参数用于该内核线程的命名;
1 #define create_workqueue(name) 2 alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name)) 3#define create_freezable_workqueue(name) 4 alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND |5 WQ_MEM_RECLAIM, 1, (name)) 6#define create_singlethread_workqueue(name) 7 alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)
这样就会在每个处理器上创建工作者线程,并准备好开始处理工作之前的准备工作;
创建一个工作的时候无须考虑工作队列的类型,在创建之后,可以调用下面的函数;这些函数与schedule_work()相似,唯一的区别是它们针对给定的工作队列而不是缺省的队列进行操作;
1 bool queue_work(struct workqueue_struct *wq, 2struct work_struct *work) 34bool queue_delayed_work(struct workqueue_struct *wq, 5struct delayed_work *dwork, 6 unsigned long delay)
刷新指定的工作队列可以使用下面函数:
1 void flush_workqueue(struct workqueue_struct *wq);
结束对工作队列的使用后,可以使用下面函数释放资源:
1 void destroy_workqueue(struct workqueue_struct *wq);
原文:https://www.cnblogs.com/wanpengcoder/p/11761812.html
内容总结
以上是互联网集市为您收集整理的Linux设备驱动程序 之 工作队列全部内容,希望文章能够帮你解决Linux设备驱动程序 之 工作队列所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。