Linux中的work queue

schedule() , schedule_work() 以及schedule_timeout_interruptible()区别 schedule_timeout_interruptible() 用于在内核中进行可中断的睡眠,可以设置一个超时时间,允许在等待期间响应信号。总的来说,schedule() 用于实现任务调度和让出 CPU 给其他任务执行,而 schedule_work() 用于延迟执行工作函数以避免阻塞当前任务,适合在内核中异步执行一些工作。schedule() 和 schedule_work() 是 Linux 内核中用于任务调度的两个函数,它们的作用和使用场景有所不同。工作函数会在系统空闲时被调度执行。 阅读详情

这篇文章http://blog.sina.com.cn/s/blog_55465b470100qmrc.html

讲的非常通俗易懂,当做笔记,备份了。

 

工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。

工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化,因此本文分成两个部分对2.6.20之前和之后的版本分别做介绍。

1、2.6.0~2.6.19

数据结构:

struct work_struct {

    unsignedlong pending;

    structlist_head entry;

    void(*func)(void *);

    void*data;

    void*wq_data;

    structtimer_list timer;

};

pending是用来记录工作是否已经挂在队列上;

entry是循环链表结构;

func作为函数指针,由用户实现;

data用来存储用户的私人数据,此数据即是func的参数;

wq_data一般用来指向工作者线程(工作者线程参考下文);

timer是推后执行的定时器。

work_struct的这些变量里,func和data是用户使用的,其他是内部变量,我们可以不用太过关心。


API:

1) INIT_WORK(_work, _func, _data)

初始化指定工作,目的是把用户指定的函数_func及_func需要的参数_data赋给work_struct的func及data变量。

2) int schedule_work(struct work_struct*work)

对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。

3) int schedule_delayed_work(struct work_struct *work, unsignedlong delay)

延迟执行工作,与schedule_work类似。

4) void flush_scheduled_work(void)

刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。

5) int cancel_delayed_work(struct work_struct*work)

flush_scheduled_work并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work。


以上均是采用缺省工作者线程来实现工作队列,其优点是简单易用,缺点是如果缺省工作队列负载太重,执行效率会很低,这就需要我们创建自己的工作者线程和工作队列。

API:

1) struct workqueue_struct *create_workqueue(const char*name)

创建新的工作队列和相应的工作者线程,name用于该内核线程的命名。

2) int queue_work(struct workqueue_struct *wq, structwork_struct *work)

类似于schedule_work,区别在于queue_work把给定工作提交给创建的工作队列wq而不是缺省队列。

3) int queue_delayed_work(struct workqueue_struct *wq, structwork_struct *work, unsigned long delay)

延迟执行工作。

4) void flush_workqueue(struct workqueue_struct*wq)

刷新指定工作队列。

5) void destroy_workqueue(struct workqueue_struct*wq)

释放创建的工作队列。


下面一段代码可以看作一个简单的实作:


void my_func(void *data)

{

    char*name = (char *)data;

   printk(KERN_INFO “Hello world, my name is %s!\n”,name);

}


struct workqueue_struct *my_wq = create_workqueue(“mywq”);

struct work_struct my_work;


INIT_WORK(&my_work, my_func,“Jack”);

queue_work(my_wq, &my_work);


destroy_workqueue(my_wq);



2、2.6.20~2.6.??

自2.6.20起,工作队列的数据结构发生了一些变化,使用时不能沿用旧的方法。


数据结构:

typedef void(*work_func_t)(struct work_struct *work);

struct work_struct{

   atomic_long_t data;

    structlist_head entry;

   work_func_t func;

};


与2.6.19之前的版本相比,work_struct瘦身不少。粗粗一看,entry和之前的版本相同,func和data发生了变化,另外并无其他的变量。

entry我们不去过问,这个和以前的版本完全相同。data的类型是atomic_long_t,这个类型从字面上看可以知道是一个原子类型。第一次看到这个变量时,很容易误认为和以前的data是同样的用法,只不过类型变了而已,其实不然,这里的data是之前版本的pending和wq_data的复合体,起到了以前的pending和wq_data的作用。

func的参数是一个work_struct指针,指向的数据就是定义func的work_struct。

看到这里,会有两个疑问,第一,如何把用户的数据作为参数传递给func呢?以前有void *data来作为参数,现在好像完全没有办法做到;第二,如何实现延迟工作?目前版本的work_struct并没有定义timer。


解决第一个问题,需要换一种思路。2.6.20版本之后使用工作队列需要把work_struct定义在用户的数据结构中,然后通过container_of来得到用户数据。具体用法可以参考稍后的实作。


对于第二个问题,新的工作队列把timer拿掉的用意是使得work_struct更加单纯。首先回忆一下之前版本,只有在需要延迟执行工作时才会用到timer,普通情况下timer是没有意义的,所以之前的做法在一定程度上有些浪费资源。所以新版本中,将timer从work_struct中拿掉,然后又定义了一个新的结构delayed_work用于处理延迟执行:

struct delayed_work{

    structwork_struct work;

    structtimer_list timer;

};


下面把API罗列一下,每个函数的解释可参考之前版本的介绍或者之后的实作:

1) INIT_WORK(structwork_struct *work, work_func_t func)

2)INIT_DELAYED_WORK(struct delayed_work *work, work_func_tfunc)

3) intschedule_work(struct work_struct *work)

4) intschedule_delayed_work(struct delayed_work *work, unsigned longdelay)

5) structworkqueue_struct *create_workqueue(const char*name)

6) int queue_work(structworkqueue_struct *wq, struct work_struct*work)

7) intqueue_delayed_work(struct workqueue_struct *wq, struct delayed_work*work, unsigned long delay)

8) voidflush_scheduled_work(void)

9) voidflush_workqueue(struct workqueue_struct*wq)

10) intcancel_delayed_work(struct delayed_work*work)

11) voiddestroy_workqueue(struct workqueue_struct*wq)


其中,1), 2), 4) ,7)和以前略有区别,其他用法完全一样。


实作:


struct my_struct_t{

    char*name;

    structwork_struct my_work;

};


void my_func(structwork_struct *work)

{

    structmy_struct_t *my_name = container_of(work, struct my_struct_t,my_work);

   printk(KERN_INFO “Hello world, my name is %s!\n”,my_name->name);

}


struct workqueue_struct *my_wq = create_workqueue(“mywq”);

struct my_struct_t my_name;


my_name.name = “Jack”;


INIT_WORK(&(my_name.my_work),my_func);

queue_work(my_wq, &my_work);


destroy_workqueue(my_wq);



Linux内核经典队列queue.h详解 一、前言 相信有一定编程经验的你,在项目中经常会遇到队列、链表、ringbuffer等问题。刚开始的时候,都有过自己编写代码(造轮子)的经验。但随着工作经验的提升,经常会发现: 以前自己造的轮子还有很多漏洞,并不能满足现在或将来的产品需求;甚至已经给现有产品埋下了坑; 接触的越来越多,发现有很多经典开源的库(GitHub),已经实现了以前自己造的轮子,而且开源库做的更好(应该是非常的好)。 那... 阅读详情

相关推荐

【Linux内幕】schedule_work基本流程

1、前言 在许多情况下,设备驱动程序不需要有自己的工作队列。如果我们只是偶尔需要向队列中提交任务,则一种更简单、更有效的办法是使用内核提供的共享的默认工作队列。但是,如果我们使用了这个默认的工作队列,则应该记住我们正在和他人共享该工作队列。这意味着,我们不应该长期独占该队列,即:不能长时间休眠,而且我们的任务可能需要更长的时间才能获得处理器。 2、schedule使用步骤: 1、定义相关数据 static struct work_struct jiq_work; 2、编写要提交到工作队列中的函数 stat

平凡的世界 7644

内核的 工作队列 使用方法,struct work_struct

工作队列一般用来做滞后的工作,比如在中断里面要做很多事,但是比较耗时,这时就可以把耗时的工作放到工作队列。说白了就是系统延时调度的一个自定义函数。 1、定义struct work_struct irq_queue; 2、初始化INIT_WORK(&irq_queue,do_irq_queuework); 3、调用方法:schedule_work(&rq_queue); 注,

zhaoercheng1201的专栏 1362

实战指南:如何在Linux驱动开发中正确使用queue_work函数

本文详细介绍了在Linux驱动开发中如何正确使用queue_work函数进行异步任务处理。通过workqueue机制,开发者可以将耗时操作从中断处理程序转移到内核线程中执行,保证系统实时性。文章涵盖了基础用法、实战场景、高级技巧及常见问题调试方法,帮助开发者高效利用queue_work优化驱动性能。

weixin_42565652的博客 368

Linux中的工作队列

Linux中的工作队列  [前记]Linux自从2.6.20之后,工作队列发生了一些变化,目前从网络上搜索的资料一般都是介绍老版本的工作队列,很少见到对新版本的介绍。本文对新老版本都做了简要概述,并分别提供了简单的实作案例。******************************************************

doujiao的专栏 1003

queue_work 简介

queue_work 是 Linux 内核中 workqueue 机制的一个关键函数,用于将工作(work)提交到工作队列(workqueue)中异步执行。

六六哥的博客 1176

深入解析ADC采样电容:从充电误差到LSB精度的关键设计

本文深入解析了ADC采样电容在模数转换中的核心作用,重点探讨了充电时间常数与采样误差的博弈关系。通过推导最小采样时间公式,揭示了精度、速度、源阻抗与内部电容之间的制约关系,并提供了从理论计算到外部驱动电路设计的实战指南,是确保ADC达到LSB精度的关键。

android的专栏 1103

linux work queue的两种调度方式

第一种使用schedule_work手动调度: #include linux/init.h> #include linux/module.h> #include linux/timer.h> #include linux/time.h> #include linux/workqueue.h> #include asm/atomic.h> #includ

☆ 默默地牛逼着 5604

5nm制程的CV5芯片实测:用它给无人机做8K拍摄和实时避障,功耗和性能到底怎么样?

本文深度评测了5nm制程的CV5芯片在无人机8K拍摄和实时避障中的表现。通过实测数据展示了CV5的异构计算架构、8K视频编码性能和CVflow®AI引擎的加速效果,同时提供了开发中的优化技巧和散热建议,为无人机开发者提供了实用的参考。

weixin_30861797的博客 358

深入解析Linux内核中的queue_work与workqueue机制

本文深入解析Linux内核中的queue_work与workqueue机制,详细介绍了异步任务调度的核心思想及其在进程上下文中的优势。通过实际案例和性能优化技巧,帮助开发者理解workqueue的内部运作机制、并发管理(CMWQ)以及NUMA架构下的优化策略,提升系统性能和资源利用率。

weixin_28730131的博客 393

TekTronix 高速信号完整性基础以及测试方法分析

如果信号速率比较高,则CTLE与FFE都无法满足要求,尤其是大于10G,比如USB3.1Gen2 10Gbps,PCIe4.0 16Gbps,这些场合都会采用DFE均衡,DFE的优点是,它既可以识别当前比特,并且可以判决前面的n个比特(Tap的阶数越高,看到的前面的比特数越多),根据前面比特的变化来计算出要处理当前比特所要变化的幅度,来补偿由于前面比特变化所引起的信号幅度的变化。10G以下,一般都不太关心这个串扰,高于10G的信号,会发现相互之间的串扰越来越明显,已经成为引起误码的重要的原因之一。

weixin_45365488的博客 4142

VerilogEval实战指南:从基准测试到模型微调的全流程解析

本文提供了VerilogEval实战指南,详细解析了从基准测试到模型微调的全流程。VerilogEval是一个自动化、标准化的测试框架,用于客观评估大语言模型生成Verilog硬件代码的能力。文章涵盖了环境搭建、核心机制解析、利用其生成合成数据进行模型微调的策略,以及如何将其工程化集成到自动化评估流程中,为硬件设计领域的AI应用提供了完整的方法论。

yy01234的博客 1005

Linux设备驱动之中断---work_queue使用示例

前两篇文章介绍了中断的原理和基本框架,但是实际使用过程中会用到中断上下文的编程方法,这里介绍work_queue.我使用的硬件是imx6q,原理都一样。原来的beep引脚是output模式,电路上把它改成了按键。下面程序的文件名为interrupt_work_queue.c#include <linux/kernel.h> #include <linux/module.h> #include <li

不积硅步,无以至千里 2356

基于ArduPilot的旋翼式无人机飞行器开发系列(二,学习路线)

一,热爱 作为一名耿直的技术男,在这里我只想说一句,热爱是可持续学习的第一要素,也只有热爱才能让你坚持到最后。 至于最后能得到什么,只有你自己知道。常说书中自有颜如玉,书中自有黄金屋。如果你是为了颜如玉,我相信大多数颜如玉做不了你的红颜知己。如果是为了黄金屋,当你持续投入时间和金钱却看不到回报的时候,相信退堂鼓早已隆隆作响。 我给自己的信条就是为当下努力工作,为将来持续学习。当前飞控行业并没有爆发,如果想赚块钱,去互联网汽车,去VR/AR吧,去元宇宙吧。 那么我热爱...

从0到1,突破自己 1667

深入解析Linux内核中的workqueue机制与queue_work实现

本文深入解析Linux内核中的workqueue机制与queue_work实现,详细介绍了workqueue的核心数据结构、queue_work的执行流程以及CMWQ的并发管理策略。通过实际案例和性能对比,帮助开发者掌握如何高效使用workqueue处理延迟任务,避免常见陷阱,并提供了高级应用与自定义扩展的实用技巧。

weixin_29230805的博客 124

Python 神经计算实训 实训答案分享

【代码】Python 神经计算实训 实训答案分享。

2403_89314916的博客 346

把 SAP Fiori Launchpad Designer 的 Catalog 与 Group 传输讲透:从 CONF、CUST 到 Transport Request 的完整理解

SAP Fiori项目中,catalog和group的传输问题往往源于对FLPD层次模型的理解不足。FLPD包含configuration(系统级)和customizing(客户端级)两个层面,分别对应workbench request和customizing request传输方式。常见误区包括:混淆/UI2/FLPD_CONF和/UI2/FLPD_CUST入口、未提前创建传输请求、不了解层次覆盖机制(customizing会覆盖configuration)。当客户端修改configuration层的对象

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 101

linux work queue

Linux中的work queue  (2011-04-20 17:09:14) 转载▼ 标签:  杂谈 分类: Linux 工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在

lemontree1945的博客 443

华为OD机试真题 新系统2026-04-01 C语言 实现【空间占用计算】

员工A的磁盘空间经常被耗尽,他需要找到占用空间最大的目录或文件,然后决定如何清理文件释放空间。给定某一目录,请编写程序帮助他统计该目录内一级子目录和文件的占用空间,并返回目标目录一级子项(文件或子目录)中占用空间最大的项。

MISAYAONE的博客 230

Linux开发:工作队列work queue和延时工作队列

工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制。 这种机制和BH或Tasklets不同之处在于工作队列是把延期的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。 每个工作队列多有一个数组,数据...

Android/Linux驱动开发传帮带学习,让驱动入门门槛更低! 6640

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

linux kernel 中的work queue原理

先简单快速总结一下,更详细的剖析后续用帖子编辑方式逐步完成。 分成两大部分,第一部分是用来执行work queue中每个节点上挂载的函数的内核线程,第二部分是从驱动程序的角度看work queue的使用。 第一部分 worker_thread内核线程 Linux系统启动期间会创建一名为worker_thread线程,该线程创建之后就处于sleep状态。这里所谓的内核线程,从调度器的角

fresh_water2020的专栏 914

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

linux延时队列,Linux的工作队列work queue和延时工作队列

在linux中,当你想延时几秒或者几毫秒再执行一个任务或者自定义的一个函数时,延时工作队列是你最好的选择。在你的任务或者函数中,加上queue_delayed_work,就可以每隔一段时间执行一次你的任务或者自定义的一个函数,具体实现如下:按如下步骤:首先还是要添加上工作队列的相关头文件,头文件一般有这些函数的声明和定义,include了相关的头文件,我们才能随心所欲的使用这些头文件里面的函数,达...

weixin_34211615的博客 2293

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

linux内核中断的下半部分之三(work_queue)

基于2440&linux-2.6.36的添加work_queue的例子

zhanglong71的博客 302

Linux kernel 中的work queue原理

<br /><br /> <br /> <br />分成两大部分,第一部分是用来执行work queue中每个节点上挂载的函数的内核线程,第二部分是从驱动程序的角度看work queue的使用。<br />第一部分 worker_thread内核线程<br />Linux系统启动期间会创建一名为worker_thread线程,该线程创建之后就处于sleep状态。这里所谓的内核线程,从调度器的角度就是一可以调度的进程,从代码的表现形式看,就是一函数。系统创建的这个worker_thread线程基于一workq

kenxausten的专栏 7245
上一篇: Android安装Google程序
下一篇: Porting WiFi drivers to Android
dadahacker
博客等级 码龄20年 78粉丝 120原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值