当前课程知识点:Linux 内核分析与应用 >  第7章 内核同步 >  7.3 动手实践-内核多任务并发实例(上) >  Video

返回《Linux 内核分析与应用》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《Linux 内核分析与应用》慕课在线视频列表

Video课程教案、知识点、字幕

大家好 今天给大家带来的是动手实践

内核多任务并发实例

在前两节中

陈老师给大家讲解了有关同步的概念

和一些内核同步机制

今天我们用一个实例来看看

在Linux中是如何使用这些机制

实现复杂的多任务同步的

首先 我给大家来介绍一下我们今天要完成的这个例子

有这样一个内核共享资源

链表同时 有3种不同类型的内核任务

会访问该链表并对其进行插入或者删除结点的操作

内核线程负责向链表加入新结点

内核定时器负责

定时删除结点

而系统调用则负责在某个时候

销毁整个链表

这三种内核任务

并发执行时 有可能会破坏链表数据的完整性

所以我们必须对链表进行同步访问保护

以确保数据的一致性

在这样一个多任务并发访问的模型中

我们需要选用合适的内核同步机制

来管理这些任务

使得它们能够有条不紊的执行

我们主要用到的工具有

信号量 自旋锁

工作队列和内核定时器

在前两节的课程中

陈老师为我们详细的讲解了信号量

和自旋锁的概念

和相应的使用方法

在这里我就不再赘述了

接下来我带大家简单的复习一下

工作队列和内核定时器

在内核代码中

经常希望延缓部分工作

到将来某个时间执行

内核中提供了许多机制来实现这种延迟执行

例如可延迟函数 工作队列等

工作队列(workqueue)可以把工作推后

并交由一个特殊的内核线程

工作者线程来执行

该线程运行在进程上下文环境中

可以被阻塞

工作队列的优势

在于它允许重新调度甚至是睡眠

我们把推后执行的任务叫做工作(work)

描述它的数据结构为work_struct

这些工作以队列结构组织成工作队列(workqueue)

其数据结构为workqueue_struct

工作队列的实现原理

当用户初始化一个工作队列时

内核就开始为用户分配一个workqueue

工作队列对象

并且将其链到一个全局的workqueue队列中

然后Linux会根据当前CPU的情况

为工作队列对象分配

与CPU个数相同的cpu_workqueue_struct也就是

cpu工作队列对象

每个cpu工作队列对象都会有一条任务队列

Linux会为每一个cpu工作队列对象

分配一个内核线程

即daemon守护进程

用来处理每个任务队列中的任务

至此 工作队列的初始化就完毕了

将会返回一个指向工作队列的指针

在工作队列初始化完毕之后呢

是将任务运行的上下文环境构建了起来

但是还没有具体可执行的任务

任务队列为空 那么内核守护进程就在

cpu_workqueue_struct的中

这个等待队列上睡眠
cpu_workqueue_struct的中

这个等待队列上睡眠

所以 我们还需要定义具体的work_struct工作对象

然后将work_struct加入到任务队列中

Linux就会唤醒守护进程去处理相应的任务

在Workqueue工作队列机制中

内核在系统初始化的时候

已为我们创建好了默认的工作队列keventd_wq

我们在使用的时候可以

不需要再创建工作队列

只需要创建工作 并将工作添加到

内核工作队列keventd上即可

当然 我们也可以创建并使用自己的工作队列

工作队列常用的API

使用工作队列的一般流程为

1.定义声明工作处理函数function

指向工作队列的指针

和工作结构体变量work_struct

我们这里使用DECLARE_WORK

或者INIT_WORK这两个宏

来指定工作处理函数

第二步调用create_singlethread_workqueue

或者create_workqueue

函数来创建自己的工作队列

这两个函数的区别在于

create_workqueue这个函数呢它创建一个工作队列

并且为系统中每一个CPU

都会创建一个内核线程守护进程

去监视

相应的任务队列

而create_singlethread_workqueue

它只会创建一个内核线程

一个内核的守护进程

这里呢我们如果使用内核默认的

工作队列kevent 也可以省去这一步

第三步我们需要将

工作添加到自己创建的工作队列中等待执行

这里我们使用的函数是queue_work

调度执行一个指定workqueue中的任务

需要传入的参数就是指定workqueue的指针

还有一个具体任务对象的指针

同样的我们这里如果使用内核工作队列kevent的话

我们需要用到另一个函数schedule_work

它是调度执行一个具体的任务

并将执行的任务

挂入到Linux系统提供的工作队列kevent中

最后一步就是删除自己的工作队列

我们这里使用destroy_workqueue这样一个函数

释放我们创建的工作队列

如果我们使用内核工作队列

这一步也可以被省略

关于工作队列的部分就是这些

下面给大家介绍的是内核定时器

内核定时器 也称为动态定时器

是管理内核时间的基础

它是一种用来推迟执行程序的工具

在2.4之前老版本中有静态定时器的概念

而2.4之后静态定时器就被完全去掉了

我们在使用关于定时器的相关函数时

先来看看内核是如何描述定时器的

内核用timer_list

这样的数据结构来描述内核定时器

其中包含了这样几个重要的成员

entry是定时器hlist 链表的入口

expires 是定时器到期时的tick数

系统当前的tick数保存在一个名为jiffies的全局变量中

有关tick和jiffies

我会在接下来的PPT中给大家详细讲述

接着呢是一个函数指针

它是用来

指定定时器到期时的处理函数的

最后这个Flag 呢是传给定时器处理函数所需要的参数的

在Linux系统中

时钟分为硬件时钟和软件时钟

软件时钟又叫做系统时钟

在对内核编程中 我们经常用到的是系统时钟

系统时钟的初始值在系统启动时

通过读取硬件时钟来获得

然后由Linux内核来维护

系统时钟以某种频率触发时钟中断

这个频率就称为节拍率(tick rate)

节拍率是通过静态预处理定义的

被定义为HZ

内核会根据HZ值 设置时钟事件

启动tick节拍中断

HZ表示1秒内产生多少个时钟硬件中断

tick就表示连续两个中断的间隔时间

使用如下的命令 可以查看HZ数

HZ=250

所以在我的电脑上一个tick为4ms

而名为 jiffies 全局变量

是用来记录系统启动以来所经过的节拍数的

动态定时器 动态二字是指

内核的定时器队列是可以动态变化的

其关键就在于“定时器向量”的概念

所谓“定时器向量”就是指一条定时器队列

队列中的每一个元素

都是一个timer_list结构

而队列中所有的定时器

都会在同一个时刻到期

也就是说队列中每一个timer_list结构

都具有相同的expires值

不同的定时器队列根据其expires值不同

再连接成为一个双向循环的队列

定时器expires值与jiffies变量的差值

决定了一个定时器在多长时间后到期

在32位系统中

这个时间差值的最大值

应该为2的32次方

如果是基于“定时器向量”的定义

那么内核将要至少

维护2的32次方个timer_list结构类型的指针

这显然是不现实的 另一方面

从内核本身来看

它所关心的定时器应当是那些当前已经到期

或者马上就要到期的定时器

所以 对于即将到期的定时器

Linux会严格按照

定时器向量的基本定义来组织它们

将最近到期的定时器

按照各自不同的expires值

组织成256个定时器向量

对于其他的定时器

由于他们离到期还有一段时间

因此内核并不关心他们

而是将它们组织在一个松散的队列中

即各定时器的expires值可以互不相同的一个定时器队列

这种定时器组织形式的基本思想

想就来源于时间轮 (Timing-Wheel) 算法

另外 由于对定时器到期时间的检查

总是由可延迟函数进行

而可延迟函数被激活以后

很长时间才能被执行

因此 内核不能保证

定时器函数

正好在定时器到期时被执行

只能保证它们在适当的时间执行

或者说它们会在定时器到期后

延迟几百毫秒再被执行

因此 内核定时器的精度不高

对于必须严格遵守

定时时间的那些实时应用来说

应当选用hrtimer高精度定时器

内核定时器常用的API

使用内核定时器的一般流程为

1定义timer_list结构 编写回调函数

2为timer初始化

为其expires flag function等成员赋值

我们这里使用define_timer

或者timer_setup

这两个宏来初始化内核定时器

第三步我们需要调用add_timer

将定时器添加到系统中

或者我们可以直接调用这个mod_timer这样一个函数

该函数原本是用来修改一个定时器的

超时时间的

这里也可以用它来激活一个定时器

第四步呢当定时器到期时呢 回调函数将会被执行

第五步也就是最后一步

我们需要在程序中适当地调用del_timer

或者mod_timer

来删除定时器或者改动定时器的到期时间

好了 了解了这些 我们就可以来一同看看

代码是如何实现的

Linux 内核分析与应用课程列表:

第1章 概述

-1.1 Linux操作系统概述

--1.1 Linux 操作系统概述

-1.2 Linux内核结构以及内核模块编程

--Video

-1.3 Linux内核源码中的双链表结构

--Video

-1.4 源码分析-内核中的哈希表

--Video

-1.5 动手实践-Linux内核模块的插入和删除

--Video

-第1章 概述--章节测验

-第1章导学--引领你进入Linux内核的大门

第2章 内存寻址

-2.1 内存管理之内存寻址

--Video

-2.2 段机制

--Video

-2.3分页机制

--Video

-2.4 动手实践-把虚拟地址转换成物理地址

--Video

-第2章 内存寻址--章节测验

-第二章导学-从零打造自己的操作系统

第3章 进程管理

-3.1 进程概述

--Video

-3.2 Linux进程创建

--Video

-3.3 Linux进程调度

--Video

-3.4 动手实践-打印进程描述符task_struct中的字段

--Video

-3.5工程实践-基于内核模块的负载监控

--Video

-第3章 进程管理--章节测验

-第三章导学-进程背后琳琅满目的宝贝到哪里挖?

第4章 内存管理

-4.1 Linux内存管理机制

--Video

-4.2 进程用户空间管理机制

--Video

-4.3 物理内存分配与回收机制(上)

--Video

-4.4 物理内存分配与回收机制(下)

--Video

-4.5 动手实践-Linux内存映射基础(上)

--Video

-4.6 动手实践-Linux内存映射实现(中)

--Video

-4.7 动手实践-Linux内存映射测试(下)

--Video

-4.8 初学者对内存管理的常见疑惑

--初学者对内存管理的常见疑惑(一)

--初学者对内存管理的常见疑惑(二)

--初学者对内存管理的常见疑惑(三)

-第4章 内存管理--章节测验

第5章 中断

-5.1 中断机制概述

--Video

-5.2 中断处理机制

--Video

-5.3 中断下半部处理机制

--Video

-5.4 时钟中断机制

--Video

-5.5 动手实践-中断上半部的代码分析及应用

--Video

-5.6 动手实践-中断下半部的代码分析及应用

--Video

-第5章 中断--章节测验

第6章 系统调用

-6.1 Linux中的各种API

--Video

-6.2 系统调用机制

--Video

-6.3 动手实践-添加系统调用(系统调用日志收集系统)

--Video

-第6章 系统调用--章节测验

第7章 内核同步

-7.1 内核同步概述

--Video

-7.2 内核同步机制

--Video

-7.3 动手实践-内核多任务并发实例(上)

--Video

-7.4 动手实践-内核多任务并发实例(下)

--Video

-第7章 内核同步--章节测验

第8章 文件系统

-8.1 虚拟文件系统的引入

--Video

-8.2 虚拟文件系统的主要数据结构

--Video

-8.3 文件系统中的各种缓存

--Video

-8.4 页高速缓存机制以及读写

--Video

-8.5 动手实践-编写一个文件系统(上)

--Video

-8.6 动手实践-编写一个文件系统(中)

--Video

-8.7 动手实践-编写一个文件系统(下)

--Video

-第8章 文件系统--章节测验

第9章 设备驱动

-9.1 设备驱动概述

--Video

-9.2 I/O空间管理

--Video

-9.3 设备驱动模型

--Video

-9.4 字符设备驱动程序简介

--Video

-9.5 块设备驱动程序简介

--Video

-9.6 动手实践-编写字符设备驱动程序

--Video

-9.7工程实践-编写块设备驱动的基础(上)

--Video

-9.8 工程实践-块设备驱动程序分析(中)

--Video

-9.9 工程实践-块设备驱动程序实现(下)

--Video

-第9章 设备驱动--章节测验

致谢与说明

-致谢与说明

--Video

直播视频:从Linux内核学习到自主操作系统研发

-从Linux内核学习到自主操作系统研发

附录:实验代码、课件以及相关素材

-各章实验代码

-《Linux内核分析与应用》课件

-《Linux操作系统原理与应用》教材课堂视频

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。