专栏首页科技分享linux工作队列 - workqueue总览

linux工作队列 - workqueue总览

转自:https://blog.csdn.net/cc289123557/article/details/52551176

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/l289123557/article/details/52551176

文章系列 1.linux工作队列 - workqueue总览 2.linux工作队列 - workqueue_struct创建 3.linux工作队列 - 把work_struct加入工作队列 4.linux工作队列 - work_struct被调用过程

1.介绍 1.1工作队列介绍 有许多情况下需要异步执行进程上下文,在linux中工作队列(wq)是处理这种情况最常用的机制。在处理中断中,对于中断下半部的处理最常用的就是wq。

1.2CMWQ 在原有的wq实现中,一个多线程wq(MT wq)有一个per CPU worker线程,一个单线程wq有一个系统范围的worker线程。多线程wq(MT wq)的数量保持和cpu的个数一致,随着近年来cpu core个数的增加,多线程wq(MT wq)的增加已经使得系统在32k PID的控件接近饱和。

虽然MT wq消耗了大量资源,但是提供的并发执行水平还是得不到满足。即使MT有很少的服务但是ST wq和MT wq还是有限制。每个wq有自己单独的worker pool,MTwq智能在per CPU执行,而STwq可以在整个系统执行。

CMWQ(Concurrency Managed Workqueue)是对原有wq的一个重新实现,主要解决以下问题: a. API要能够兼容以前的wq实现 b. 使用per-CPU的worker pool要能够被所有的wq所共享,以便提供更好的并发灵活性,以免浪费资源 c. 对于使用者要隐藏细节

2.workqueue设计框架 工作队列的整体设计框架如下图,这里有多个结构体,他们之间的关系下面说明

work_struct结构体代表的是一个任务,它指向一个待异步执行的函数,不管驱动还是子系统什么时候要执行这个函数,都必须把work加入到一个workqueue。

worker结构体代表一个工作者线程(worker thread),它主要一个接一个的执行挂入到队列中的work,如果没有work了,那么工作者线程就挂起,这些工作者线程被worker-pool管理。

对于驱动和子系统的开发人员来说,接触到的只有work,而背后的处理机制是管理worker-pool和处理挂入的work,这就是CMWQ设计的不同。

worker-pool结构体用来管理worker,对于每一种worker pool都分两种情况:一种是处理普通work,另一种是处理高优先级的work。

workqueue_struct结构体代表的是工作队列,工作队列分unbound workqueue和bound workqueue。bound workqueue就是绑定到cpu上的,挂入到此队列中的work只会在相对应的cpu上运行。unbound workqueue不绑定到特定的cpu,而且后台线程池的数量也是动态的,具体workqueue关联到哪个worker pool,这是由workqueue_attrs决定的。

3.workqueue用法 工作队列从字面意义上很好理解,虽然背后的实现机制有点复杂,但是使用的时候还是简单方便的,对于使用者来说,我们只要定义一个work,然后把work加入到workqueue。如果当前没有我们需要的workqueue,那么我们需要自己创建一个。

下文各个API的具体说明见include/linux/workqueue.h

3.1workqueue_struct创建与销毁 //创建workqueue_struct

#define alloc_ordered_workqueue(fmt, flags, args...) \ alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)

#define create_workqueue(name) \ alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))

#define create_freezable_workqueue(name) \ alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND | \ WQ_MEM_RECLAIM, 1, (name))

#define create_singlethread_workqueue(name) \ alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)

//销毁workqueue_struct extern void destroy_workqueue(struct workqueue_struct *wq); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 由上可以看出workqueue的创建根据flag的不同会创建不同种类的workqueue,但最终都会调用到接口alloc_workqueue,具体workqueue创建的过程及代码分析见文章linux工作队列 - workqueue_struct创建。

3.2初始化work_struct #define INIT_WORK(_work, _func) \ __INIT_WORK((_work), (_func), 0)

#define INIT_WORK_ONSTACK(_work, _func) \ __INIT_WORK((_work), (_func), 1) #define INIT_DELAYED_WORK(_work, _func) \ __INIT_DELAYED_WORK(_work, _func, 0)

#define INIT_DELAYED_WORK_ONSTACK(_work, _func) \ __INIT_DELAYED_WORK_ONSTACK(_work, _func, 0)

#define INIT_DEFERRABLE_WORK(_work, _func) \ __INIT_DELAYED_WORK(_work, _func, TIMER_DEFERRABLE)

#define INIT_DEFERRABLE_WORK_ONSTACK(_work, _func) \ __INIT_DELAYED_WORK_ONSTACK(_work, _func, TIMER_DEFERRABLE) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 3.3把work_struct加入工作队列 extern bool queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work); extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay); extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay); 1 2 3 4 5 6 具体代码分析见linux工作队列 - 把work_struct加入工作队列 ———————————————— 版权声明:本文为CSDN博主「鸭蛋西红柿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/cc289123557/article/details/52551176

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python里的OS与SYS

    os.name字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。

    我被狗咬了
  • RocketMQ Broker启动流程梳理

    org.apache.rocketmq.broker.BrokerStartup:

    张乘辉
  • 如何正确的使用VSCode

    由与我们的Coding工作比较辛苦,现在推荐大家一款VS code插件,专注于高(hun)效(shui)工(mo)作(yu),能让你更加高效的上(hua)班(s...

    我被狗咬了
  • 教你如何用Jenkins自动化部署项目(教程,从零到搭建完成)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    拓荒者
  • CentOS + Jenkins

    (adsbygoogle = window.adsbygoogle || []).push({});

    拓荒者
  • Java NIO之理解I/O模型(二)

    上一篇文章讲解了I/O模型的一些基本概念,包括同步与异步,阻塞与非阻塞,同步IO与异步IO,阻塞IO与非阻塞IO。这次一起来了解一下现有的几种IO模型,以及高效...

    Jimoer
  • 让你的SSH连接提示更加个性化

    我们经常使用ssh工具登录服务器,经常会看到提示信息,有没有人想到把提示信息修改成自己喜欢的东西呢?

    我被狗咬了
  • python基础五

    常用print()#输出,input()#交互输入,open()#文件操作等都不说了。

    不断折腾
  • 系列 | 漫谈数仓第一篇NO.1 『​基础架构』

    离线数据仓库到实时数据仓库,从lambda架构到kappa架构、再到混合架构。本文不再多再介绍,之前文章已有深入介绍,如有兴趣可看这篇文章:数据仓库介绍与阿里实...

    Spark学习技巧
  • CentOS下Jenkins的安装和使用

    Jenkins 是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更为重要的业务逻辑实现上。同时 Jenkins 能实施监...

    拓荒者

扫码关注云+社区

领取腾讯云代金券