linux平台下 延迟工作队列实例
工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制。
这种机制和BH或Tasklets不同之处在于工作队列是把延期的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
每个工作队列多有一个数组,数据元素的数目与内核处理器core的数目相同,每个数据元素都列出来将要延期执行的任务。
对于每个工作队列来说,内核都会创建一个新的内核守护线程,延期任务使用上下文描述的等待队列机制,在守护进程的上下午执行。
先定义几个内核中使用工作队列时用到的术语方便后面描述。
- workqueues:所有工作项被 ( 需要被执行的工作 ) 排列于该队列,因此称作工作队列 (workqueues) 。
- worker thread:工作者线程 (worker thread) 是一个用于执行工作队列中各个工作项的内核线程,当工作队列中没有工作项时,该线程将变为 idle 状态。
- single threaded(ST)::工作者线程的表现形式之一,在系统范围内,只有一个工作者线程为工作队列服务
- multi threaded(MT):工作者线程的表现形式之一,在多 CPU 系统上每个 CPU 上都有一个工作者线程为工作队列服务
如何使用工作队列哪?按如下步骤:
一. 声明一个工作队列
staticstruct workqueue_struct *test_wq;
二. 声明一个延期工作描述实例
static struct delayed_work test_dwq;
三. 声明并实现一个工作队列延迟处理函数
voiddelay_func(struct work_struct *work);
voiddelay_func(struct work_struct *work)
{
printk(KERN_INFO "My name isdelay_func!\n");
}
四. 初始化一个工作队列
test_wq = create_workqueue("test_wq");
五. 任务初始化
INIT_DELAYED_WORK(&test_dwq,delay_func);
六. 向工作队列提交工作项
queue_delayed_work(test_wq, &test_dwq, delay);
七. 取消工作队列中的工作项
int cancel_delayed_work(test_wq);
如果这个工作项在它开始执行前被取消,返回值是非零。内核保证给定工作项的执行不会在调用 cancel_delay_work 成功后被执行。 如果 cancel_delay_work 返回 0,则这个工作项可能已经运行在一个不同的处理器,并且仍然可能在调用 cancel_delayed_work 之后被执行。要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行,你必须跟随这个调用之后接着调用 flush_workqueue。在 flush_workqueue 返回后。任何在改调用之前提交的工作函数都不会在系统任何地方运行。
八. 刷新工作队列
flush_workqueue(test_wq);
九. 工作队列销毁
destroy_workqueue(test_wq);
涉及到的主要函数与结构体
一. 函数queue_delayed_work()
函数queue_delayed_work()是用于向工作队列提交delayed_work实例,确保在延期执行之前,至少会经过由delay指定的一段时间(以jiffies为单位)。
该函数首先创建一个由内核定时器,该定时器将在delayed jiffies之内超时。
二. 延期工作描述实例
structdelayed_work {
struct work_struct work; /* 将作为实例被queue_work或queue_work_delayed添加到一个工作队列*/
struct timer_list timer; /* 延迟时间*/
};
三. alloc_workqueue函数
struct workqueue_struct *alloc_workqueue(char *name, unsigned intflags, int max_active);
name:为工作队列的名字,而不像 2.6.36 之前实际是为工作队列服务的内核线程的名字。
Flag: 指明工作队列的属性,可以设定的标记如下:
- WQ_NON_REENTRANT:默认情况下,工作队列只是确保在同一 CPU 上不可重入,即工作项不能在同一 CPU 上被多个工作者线程并发执行,但容许在多个 CPU 上并发执行。但该标志标明在多个 CPU 上也是不可重入的,工作项将在一个不可重入工作队列中排队,并确保至多在一个系统范围内的工作者线程被执行。
- WQ_UNBOUND:工作项被放入一个由特定 gcwq 服务的未限定工作队列,该客户工作者线程没有被限定到特定的 CPU,这样,未限定工作者队列就像简单的执行上下文一般,没有并发管理。未限定的 gcwq 试图尽可能快的执行工作项。
- WQ_FREEZEABLE:可冻结 wq 参与系统的暂停操作。该工作队列的工作项将被暂停,除非被唤醒,否者没有新的工作项被执行。
- WQ_MEM_RECLAIM:所有的工作队列可能在内存回收路径上被使用。使用该标志则保证至少有一个执行上下文而不管在任何内存压力之下。
- WQ_HIGHPRI:高优先级的工作项将被排练在队列头上,并且执行时不考虑并发级别;换句话说,只要资源可用,高优先级的工作项将尽可能快的执行。高优先工作项之间依据提交的顺序被执行。
· WQ_CPU_INTENSIVE:CPU 密集的工作项对并发级别并无贡献,换句话说,可运行的 CPU密集型工作项将不阻止其它工作项。这对于限定得工作项非常有用,因为它期望更多的 CPU 时钟周期,所以将它们的执行调度交给系统调度器。
· WQ_DRAINING:internal: workqueue is draining
· WQ_RESCUER :internal: workqueue has rescuer
· WQ_MAX_ACTIVE: I like 512, better ideas?
· WQ_MAX_UNBOUND_PER_CPU: 4 * #cpus for unbound wq
· WQ_DFL_ACTIVE:等于WQ_MAX_ACTIVE / 2,
max_active:决定了一个 wq 在 per-CPU 上能执行的最大工作项。比如 max_active 设置为 16 表示一个工作队列上最多 16 个工作项能同时在 per-CPU 上同时执行。当前实行中,对所有限定工作队列,max_active 的最大值是 512,而设定为 0 时表示是 256;而对于未限定工作队列,该最大值为:MAX[512,4 * num_possible_cpus() ],除非有特别的理由需要限流或者其它原因,一般设定为 0 就可以了
实例
/********************************************** * Author: lewiyon@hotmail.com * File name: delay_wq.c * Description: learn delay workqueue * Date: 2011-12-21 *********************************************/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/workqueue.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/interrupt.h> static struct workqueue_struct *test_wq; static struct delayed_work test_dwq; void delay_func(struct work_struct *work); void delay_func(struct work_struct *work) { printk(KERN_INFO "My name is delay_func!\n"); } static int __init example_init(void) { test_wq = create_workqueue("test_wq"); if (!test_wq) { printk(KERN_ERR "No memory for workqueue\n"); return 1; } printk(KERN_INFO "Create Workqueue successful!\n"); INIT_DELAYED_WORK(&test_dwq, delay_func); queue_delayed_work(test_wq, &test_dwq, 0); return 0; } static void __exit example_exit(void) { destroy_workqueue(test_wq); printk(KERN_INFO "Goodbay!\n"); } module_init(example_init); module_exit(example_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lewiyon <lewiyon@hotmail.com>");
posted on 2011-12-23 23:25 YoungerChina 阅读(1011) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人