linux内核工作队列

Linux内核工作队列workqueue详解 linux 内核 workqueue详解 阅读详情
Workqueue 是内核里面很重要的一个机制,特别是内核驱动,一般的小型任务 (work) 都不会自己起一个线程来处理,而是扔到 Workqueue 中处理。Workqueue 的主要工作就是用进程上下文来处理内核中大量的小任务。所以 Workqueue 的主要设计思想:一个是并行,多个 work 不要相互阻塞;另外一个是节省资源,多个 work 尽量共享资源 ( 进程、调度、内存 ),不要造成系统过多的资源浪费。为了实现的设计思想,workqueue 的设计实现也更新了很多版本。最新的 workqueue 实现叫做 CMWQ(Concurrency Managed Workqueue),也就是用更加智能的算法来实现“并行和节省”。新版本的 workqueue 创建函数改成 alloc_workqueue(),旧版本的函数 create_workqueue() 逐渐会被被废弃。

使用工作队列分成两种情况:一种是利用系统自有的共享工作队列;另一种是创建自定义的工作队列。
#系统共享的工作队列机制
	(1)定义一个工作处理函数,函数声明为:
		static void my_work_func(struct work_struct *work);
	(2)定义一个工作,并为其指定工作处理函数:(有两种类型的work,如下)
		/* ①定义普通的工作--work */
		struct work_struct my_work; 
		INIT_WORK(&my_work, my_work_func);
	
		/* ②定义可以延时提交的工作--delay work */ 
		struct delayed_work my_delayed_work;
		INIT_DELAYED_WORK(&my_delayed_work, my_work_func);
	(3)将工作添加到系统的共享队列:
		/* ①将普通的work添加到工作队列中,立即提交 */
		schedule_work(&my_work);
		/* ②延时hz个时钟滴答后再提交工作 */ 
		int delay = 5;
		unsigned int hz = round_jiffies_relative(HZ * delay);
		schedule_delayed_work(&my_delayed_work, hz);
		工作执行完成后会自动从系统的共享队列中删除。
	(4)终止工作:
		/* ①终止普通工作队列中的某一个work */
		cancel_work_sync(&my_work);
		/* ②终止延时工作队列中的某一个work */
		cancel_delayed_work_sync(&my_delayed_work);

#自定义工作队列
	(1)创建一个自定义工作队列
		struct workqueue_struct *my_wq = alloc_workqueue(“my_work_queue”,WQ_UNBOUND|WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0)
	(2)定义一个工作处理函数,函数声明为:
		static void my_work_func(struct work_struct *work);
	(3)定义一个工作,并为其指定工作处理函数:
		/* ①定义普通的工作 */ 
		struct work_struct my_work;
		INIT_WORK(&my_work, my_work_func);		
		/* ②定义可以延时提交的工作 */
		struct delayed_work my_delayed_work;
		INIT_DELAYED_WORK(&my_delayed_work, my_work_func);
	(4)将工作添加到自己的工作队列:
		/* ①立即提交工作 */
		queue_work(my_wq, &my_work);
		/* ②延时hz个时钟滴答后再提交工作 */
		int delay = 5;
		unsigned int hz = round_jiffies_relative(HZ * delay);
		queue_delayed_work(my_wq, &my_delayed_work, hz);
	(5)销毁工作队列
		/* 销毁工作队列 */
		if (my_wq){
		  destroy_workqueue(my_wq);
		  my_wq = NULL;
		}
	(6)清理任务
		/* 等待工作队列中的任务完成 */
		flush_workqueue(my_wq);
	

/*******************************************************************************************************************/		
	例如:
		#我们自己定义了一个请求工作,(其中work作为我们请求工作的一个成员)
		struct readahead_req{
			unsigned long ino;
			pid_t pid;
			struct address_space *mapping;
			/*struct file_ra_state *ra;*/
			struct file *filp;
			struct page *page;
			pgoff_t offset;
			unsigned long req_size;
			struct readahead_req *pre;
			struct readahead_req *next;
			//struct delayed_work my_delayed_work;	    /* 用于延时工作队列 */
			struct work_struct my_work;	    /* 用于普通工作队列 */
		};
		#定义工作处理函数
		int async_readahead(struct work_struct *work)
		{
			/* 用于延时工作队列 */
			//struct readahead_req *req = container_of(work, struct readahead_req, my_delayed_work.work);
			//注意第一个参数work不要动,第三个work.work为delayed_work.work




			/* 用于普通工作队列 */
			struct readahead_req *req = container_of(work, struct readahead_req, my_work);
		}
		#定义一个自定义工作队列
		/*  定义延时工作队列 */
		//struct workqueue_struct *my_delayed_wq = create_workqueue("my_delayed_queue");
		
		/* 定义普通工作队列 */
		struct workqueue_struct *my_wq = alloc_workqueue(“my_queue”,WQ_UNBOUND|WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0)
		
		#初始化队列
			struct readahead_req *req = (struct readahead_req *)kmalloc(struct readahead_req);
			/* 用于延时工作队列 */
			//INIT_DELAYED_WORK(&req->my_delayed_work, async_readahead);
			
			/* 用于普通工作队列 */
			INIT_WORK(&req->my_work, async_readahead);
			
		#入队列
			/* 用于延时工作队列 */
			queue_delayed_work(&req->my_delayed_work);//好用,亲测
			//schedule_delayed_work(&req->my_delayed_work); //未用过
			
			/* 用于普通工作队列 */
			queue_work(my_wq, &req->my_work);
		#取消一个工作
			/* 用于延时工作队列 */
			cancel_delayed_work_sync(&req->my_delayed_work);
			cancel_delayed_work(&req->my_delayed_work);
			
			/* 用于普通工作队列 */
			cancel_work_sync(&req->my_work);
		#清理任务
			/* 用于延时工作队列 */
			flush_workqueue(my_delayed_wq);			
			flush_workqueue(my_wq);
		#销毁工作队列
			destroy_workqueue(my_delayed_wq);
			destroy_workqueue(my_wq);
			
			/* 一般如下使用 */
			cancel_delayed_work_sync(&req->my_delayed_work);
			flush_workqueue(my_delayed_wq);
			if (my_delayed_wq)
			{
				destroy_workqueue(my_delayed_wq);
				my_delayed_wq = NULL;
			}
					
		
/**************************************************************************************************************/

#函数解析:
struct workqueue_struct *alloc_workqueue(char *name, unsigned int flags, int max_active);(1)name:为工作队列的名字,而不像 2.6.36 之前实际是为工作队列服务的内核线程的名字。(2)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_MAX_ACTIVE: I like 512, better ideas?WQ_MAX_UNBOUND_PER_CPU: 4 * #cpus for unbound wqWQ_DFL_ACTIVE:等于WQ_MAX_ACTIVE / 2,
(3)max_active:决定了一个 wq 在 per-CPU 上能执行的最大工作项。比如 max_active 设置为 16 表示一个工作队列上最多 16 个工作项能同时在 per-CPU 上同时执行。当前实行中,对所有限定工作队列,max_active 的最大值是 512,而设定为 0 时表示是 256;而对于未限定工作队列,该最大值为:MAX[512,4 * num_possible_cpus() ],除非有特别的理由需要限流或者其它原因,一般设定为 0 就可以了。
参考资料:https://www.ibm.com/developerworks/cn/linux/l-cn-cncrrc-mngd-wkq/
详解linux 内核工作队列 阅读详情

相关推荐

Linux内核中断--工作队列工作队列管理

中断处理程序(上半部)要求执行速度极快,不能阻塞,以快速响应硬件。但在实际应用场景中,很多中断后需要进行的操作是耗时的,例如处理大量数据、读写磁盘、与用户空间通信等。共享工作队列虽然简单易用,但在某些场景下存在局限性:•隔离性问题:所有任务共享同一队列,一个耗时任务可能阻塞其他任务。•优先级控制不足:无法为特定任务设置优先级。•并发性限制:无法针对特定工作负载优化并发度。•资源控制缺失:无法限制特定队列的资源使用。自定义工作队列通过为特定任务创建专用队列和工作者线程来解决这些问题。// 工作项。

qq_40170041的博客 753

Linux内核工作队列

1 Linux workqueue工作队列 Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,他显然简化了内核daemon的创建,方便了用户的编程.它总是在进程上下问进行执行,并且可以执行中断下半部操作,允许重新调度和睡眠,可以解决软中断和tasklet执行时间过长导致的系统实时性下降等问题。 2 Linux workq

weixin_44143206的博客 1144

Linux内核线程,定时器,工作队列编程实例

Linux内核线程,定时器,工作队列编程实例: 实例大概过程如下: 一.初始化 1.创建一个工作队列test_wq 2.创建一个定时器timer 3.创建一个内核线程 二.工作过程 1.定时器每隔500ms调用do_htimer 2.定时器触发工作队列调用do_work 3.工作队列触发睡眠的内核线程(唤醒睡眠线程) 三.结束 1.停止内核线程 2.取消定时器

853

工作队列(workqueue)

内核版本:Linux-2.6.32.2 工作队列类似于tasklet,它允许内核代码请求某个函数在将来被执行(不是立即执行)。 工作队列相关API定义在中。要使用工作队列有两种方式,一是自己创建一个工作队列;二是使用内核提供的工作队列(共享方式)。 一、我们先来看自己创建工作队列的方式 工作队列使用结构体struct workqueue_struct描述,要创建一个工作

Tracy Mcgrady的专栏 3850

《深入理解Linux内核》第四章 中断和异常(五)

今天让我们来看下另一个中断下半部常用的机制----work queue 一、特性 1、先激活,在某个时间点再执行函数 2、有专用的内核线程work thread 二、与可延迟函数区别 1、可延迟函数处于中断上下文,不能调用导致睡眠的函数,而work queue处于进程上下文,可以睡眠,允许调用导致睡眠的函数 三、数据结构 1、work_struct struct work_struct { unsigned long pending; struct list_head entry;

yxw0609131056的博客 819

destroy_workqueue与flush_workqueue

void flush_workqueue(struct workqueue_struct *wq)//清理指定工作队列中的所有任务 { const struct cpumask *cpu_map = wq_cpu_map(wq); int cpu; might_sleep(); lock_map_acquire(&wq->lockdep_map); lock_map_release(

QC的博客 7029

Linux内核工作队列(workqueue)详解

Linux内核工作队列(workqueue)详解

咸鱼弟的博客 1万+

Linux内核工作队列

在我的上一篇文章Linux内核:中断、软中断、tasklet中,我们已经了解了中断底半部的两种实现方式,即软中断和tasklet微线程。但是这两种方式归根结底都是采用软中断机制的,其根本上还是在中断的上下文中执行,所以这也就要求了采用这两种方式编写中断底半部,不能出现一些可能导致程序休眠或者是延迟的函数(虽然当发生中断嵌套时会生成Ksoftirq线程,但这个是不确定的,所以我们在编写程序时,还是不

JansonZhe 5614

linux内核工作队列使用总结

我总结出的内核工作队列中的4种用法。

qq_57258828的博客 173

Linux内核工作队列实例

29.1 前言 Linux中的工作队列是将工作推后执行的一种方式,通常用在中断分层机制中,因为中断函数的原则是(1)快;(2)不能睡眠或等待;因此,在中断驱动程序中,引入工作队列实现中断的分层,硬件处理在中断函数中处理,软件及其耗时操作则在Linux内核线程中实现。本小节,将介绍Linux内核队列及其使用方式。 29.2 工作队列特点 (1)工作队列中是可以阻塞或睡眠的; (2)调用sch...

Chasing_Chasing的博客 1326

Linux 内核中的工作队列:从底半部到异步处理

/ 工作函数// 模块初始化// 创建自定义工作队列if (!my_wq) {// 初始化工作// 调度工作到自定义工作队列return 0;// 模块退出// 刷新工作队列// 销毁工作队列Linux 内核中的工作队列是实现异步任务处理的核心机制。工作队列通过工作、工作队列、工作者线程等组件,实现了任务的异步执行和资源的高效管理。工作也要流程化,工作队列就像是系统中的任务调度工具,它确保了任务的异步执行和系统的高效运行。

jiang_style的博客 1703

Linux 驱动开发 - 内核共享工作队列

内核共享工作队列是一种机制,允许驱动程序将耗时的任务委派给内核线程池来执行。这有助于提高驱动程序的响应能力和效率,同时避免内核死锁。本指南介绍了如何在 Linux 驱动程序中使用内核共享工作队列。本指南介绍了如何在 Linux 驱动程序中使用内核共享工作队列。通过遵循提供的算法和代码示例,开发人员可以创建高效且响应迅速的驱动程序。

走向CTO的路上... 1583

Linux内核工作队列使用

VERSION:5.4.24 参考: include/linux/workqueue.h 实际需要 定时器、下半部 tasklet,它们都是在中断上下文中执行,它们无法休眠。当要处理更复杂的事情时,往往更耗时。这些更耗时的工作放在定时器或是下半部中,会使得系统很卡;并且循环等待某件事情完成,这样太浪费 CPU 资源了。 如果使用线程来处理这些耗时的工作,那就可以解决系统卡顿的问题:因为线程可以休眠。 在内核中,我们并不需要自己去创建线程,可以使用“工作队列”(workqueue)。内核初始化工作队列时,就为

开发界里的一股清流 635

linux内核 队列末尾,Linux内核工作队列

Linux内核中实现工作推后执行的方法有:软中断、tasklet和工作队列(work queue)。本文介绍工作队列的简单用法。一、工作任务定义Linux内核中的工作队列包括:共享工作队列和自定义工作队列。区别如下:1)共享工作队列:将新创建的工作任务添加到Linux内核创建的全局工作队列system_wq中;2)自定义工作队列:将新创建的工作任务添加到自己创建的工作队列中;1、共享工作队列1)、...

weixin_33828635的博客 539

Linux 内核工作队列与共享队列简介

共享工作队列:适合轻量级、临时性任务,简化代码但缺乏隔离性。私有工作队列:适用于高频、高优先级或需资源隔离的任务,提供更精细的控制。设计选择:根据任务延迟敏感性、并发需求和系统负载选择队列类型,必要时结合WQ_UNBOUND等标志优化多核性能。

weixin_42369760的博客 1306

Linux内核学习之工作队列

Author : Toney Email : vip_13031075266@163.com Date : 2020.12.02 Copyright: 未经同意不得转载!!! Version : Linux-2.6.12 Reference:https://www.linux.org/ ...

遇见你是我最美丽的意外 6957
上一篇: 虚拟文件系统——VFS
下一篇: volatile变量
AXW2013
博客等级 码龄14年 30粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值