Linux内核23-工作队列

简介: Linux内核23-工作队列

1 工作队列


Linux2.6版本中引入了工作队列概念,代替Linux2.4版本中的任务队列。用以实现注册激活某些函数,留待稍后由工作线程执行(与tasklet的处理类似)。

虽然,tasklet之类的可延时函数和工作队列处理流程类似,但是却大有不同。主要的差别是可延时函数运行在中断上下文中,而工作队列中的函数运行在进程上下文中。在进程上下文运行是执行阻塞函数的唯一方式,因为中断上下文中不能发生进程切换。不论是可延时函数还是工作队列中的函数都不能访问进程的用户态地址空间,它们都运行在内核态。事实上,可延时函数并不知道当前正在运行的进程。另一方面,工作队列中函数由内核线程执行,所以也就没有用户态地址可以访问。

也就是说,工作队列的出现就是解决tasklet不能处理可阻塞函数的弊端。并且它们都是运行在内核态的程序,不能访问用户态地址空间。


1.1 工作队列数据结构


工作队列的主要数据结构是workqueue_struct,其中,包含一个具有NR_CPUS个元素的数组。每个元素都是一个类型为cpu_workqueue_struct的描述符,其成员如下表所示:

表4-12 cpu_workqueue_struct结构成员

名称 描述
lock 保护数据结构的自旋锁
remove_sequence flush_workqueue()使用的序列号
insert_sequence flush_workqueue()使用的序列号
worklist 挂起函数列表的head
more_work 休眠中的工作线程等待队列
work_done 等待从工作队列中刷新的进程队列
wq 指向包含描述符的workqueue_struct结构
thread 该数据结构的工作线程的进程描述符
run_depth run_workqueue()执行深度

worklist是一个双向链表,用来保存工作队列的待处理任务。每个待处理任务使用work_struct数据结构表示,成员如下表所示:

表4-13 work_struct成员

名称 描述
pending 1,表示处理函数已经在工作队列列表中
entry 指向函数列表中下一项或前一项
func 函数的地址
data 传给函数的数据
wq_data 指向父cpu_workqueue_struct描述符
timer 软件定时器,用于函数的延时执行


1.2 工作队列操作函数


我们已经了解了工作队列的原理,以及其数据结构。那么,当我们想要使用工作队列的时候,如何创建呢?

使用create_workqueue("foo")创建一个工作队列。foo是工作队列的名称,函数返回新创建的workqueue_struct的地址。该函数还会创建n个工作线程,n是CPU的数量,这些线程命令方式就是在传递的字符串foo后面加数字n表示:比如foo/0foo/1等等。create_singlethread_workqueue()只创建一个工作线程,其余一样。销毁工作队列使用destroy_workqueue()函数,参数是一个指向workqueue_struct结构的指针。

queue_work()函数插入一个函数到工作队列中(该函数已经被包含在work_struct描述符中了)。它的参数是指向workqueue_struct类型描述符的指针wq和指向work_struct描述符的指针work。它所执行的主要工作是:

  1. 检查待插入的函数是否已经在工作队列中。
  2. 添加work_struct描述符到工作队列列表中,设置work->pending为1。
  3. 唤醒more_work等待队列中休眠的工作线程。

queue_delayed_work()函数与queue_work()类似,除了接收第3个参数-延时时间(单位是系统嘀嗒-tick)之外。这个时间用来保证挂起函数执行之前最小延时时间。queue_delayed_work()依赖于work_struct描述符中的timer软件定时器,推迟将work_struct描述符插入到工作队列列表的时间。cancel_delayed_work()取消之前插入到工作队列中的函数,前提是work_struct描述符还没有被插入到工作队列中。

每个工作线程执行worker_thread函数,循环处理挂起的函数。但是,大部分时候,线程正在休眠并且需要处理的工作。一旦被唤醒,工作线程调用run_workqueue()函数,其实就是把work_struct描述符从该线程的工作队列列表中删除,并执行相应的函数。因为工作队列函数可以阻塞,所以工作线程可以休眠且当其被恢复执行时,可以切换到其它CPU上运行。

有时候,可能需要执行完所有的工作队列函数。可以调用flush_workqueue()函数,直到所有的函数执行完。但是,这个函数不会理会在它之后被加入工作队列的函数;对于新旧添加的函数可以通过cpu_workqueue_struct描述符中的remove_sequenceinsert_sequence成员标识。


2 预定义工作队列


大部分情况下,为了运行某个函数而创建一组工作线程是多余的。因此,内核提供了一个称为events的预定义工作队列,内核开发者可以自由使用。预定义工作队列不过就是一个标准工作队列,包含不同内核和驱动层的函数。它的workqueue_struct描述符存储在keventd_wq数组中。为了使用预定义工作队列,内核提供了一些辅助函数:

表4-14 预定义工作队列辅助函数

预定义工作队列函数 等价的标准工作队列函数
schedule_work(w) queue_work(keventd_wq,w)
schedule_delayed_work(w,d)

queue_delayed_work(keventd_wq,w,d)

(任何CPU)

schedule_delayed_work_on(cpu,w,d)

queue_delayed_work(keventd_wq,w,d)

(给定CPU)

flush_scheduled_work() flush_workqueue(keventd_wq)

预定义工作队列节省了系统资源。但是另一方面,在预定义工作队列中的函数不应该阻塞较长时间:因为每个CPU中的工作队列的函数执行都是串行化的,所以,长时间的阻塞耽误其它用户的使用。

除了通用的events队列,在Linux2.6内核中还可以发现一些特定的工作队列。最重要的是kblockd工作队列,由阻塞设备层使用。


3 总结


工作队列的场合比较适用于驱动程序开发。比如说阻塞设备驱动程序(硬盘写一块数据等),这样的驱动写操作不需要立即响应,但是需要阻塞操作,其它的写硬盘动作等待这次操作完成。就可以将这样的任务放入到工作队列中,等待系统不忙的时候再进行处理。

相关文章
|
17天前
|
安全 Linux 编译器
探索Linux内核的奥秘:从零构建操作系统####
本文旨在通过深入浅出的方式,带领读者踏上一段从零开始构建简化版Linux操作系统的旅程。我们将避开复杂的技术细节,以通俗易懂的语言,逐步揭开Linux内核的神秘面纱,探讨其工作原理、核心组件及如何通过实践加深理解。这既是一次对操作系统原理的深刻洞察,也是一场激发创新思维与实践能力的冒险。 ####
|
1天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
17 6
|
2天前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
15 6
|
2天前
|
机器学习/深度学习 负载均衡 算法
深入探索Linux内核调度机制的优化策略###
本文旨在为读者揭开Linux操作系统中至关重要的一环——CPU调度机制的神秘面纱。通过深入浅出地解析其工作原理,并探讨一系列创新优化策略,本文不仅增强了技术爱好者的理论知识,更为系统管理员和软件开发者提供了实用的性能调优指南,旨在促进系统的高效运行与资源利用最大化。 ###
|
5天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
2天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
3天前
|
缓存 网络协议 Linux
Linux操作系统内核
Linux操作系统内核 1、进程管理: 进程调度 进程创建与销毁 进程间通信 2、内存管理: 内存分配与回收 虚拟内存管理 缓存管理 3、驱动管理: 设备驱动程序接口 硬件抽象层 中断处理 4、文件和网络管理: 文件系统管理 网络协议栈 网络安全及防火墙管理
20 4
|
5天前
|
人工智能 算法 大数据
Linux内核中的调度算法演变:从O(1)到CFS的优化之旅###
本文深入探讨了Linux操作系统内核中进程调度算法的发展历程,聚焦于O(1)调度器向完全公平调度器(CFS)的转变。不同于传统摘要对研究背景、方法、结果和结论的概述,本文创新性地采用“技术演进时间线”的形式,简明扼要地勾勒出这一转变背后的关键技术里程碑,旨在为读者提供一个清晰的历史脉络,引领其深入了解Linux调度机制的革新之路。 ###
|
7天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
31 4
|
8天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
下一篇
无影云桌面