Linux内核学习(七)—— 定时器和时间管理(基于Linux 2.6内核)

news/2025/2/12 3:12:34/

目录

一、内核中的时间概念

二、节拍率:HZ

实时时钟

系统定时器

三、定时器


系统定时器是一种可编程硬件芯片,能以固定频率产生定时器中断,它所对应的中断处理程序负责更新系统时间,也负责执行需要周期性运行的任务。

一、内核中的时间概念

系统定时器以某种频率自行触发定时器中断,该频率可以通过编程预定,称作节拍率(tick rate)。当定时器中断发生时,内核就通过一种特殊的中断处理程序对其进行处理。两次定时器中断发生的间隔时间就称为节拍(tick),它的大小等于节拍率分之一(1 / (tick rate))秒

下面给出一些利用定时器中断周期执行的工作:

  • 更新系统运行时间。
  • 更新实际时间。
  • 在 smp 系统上,均衡调度程序中各处理器上的运行队列。如果运行队列负载不均衡的话,尽量使它们均衡。
  • 检查当前进程是否用尽了自己的时间片。如果用尽则重新进行调度。
  • 更新资源消耗和处理器时间的统计值。

二、节拍率:HZ

系统定时器频率(节拍率)是通过静态预处理定义的,也就是 HZ(赫兹),在系统启动时按照 HZ 值对硬件进行设置。内核在 <asm/param.h> 中定义了这个值。

实时时钟

实时时钟(RTC)是用来持久存放实际时间的设备,即便系统关闭后,也可以靠主板上的微型电池保持系统的计时。当系统启动时,内核通过读取 RTC 来初始化实际时间,该时间存放在 xtime 变量中。

系统定时器

系统定时器是内核定时机制中最为重要的部分,它提供一种周期性触发中断机制。

三、定时器

定时器(也叫动态定时器或内核定时器)可以让指定的工作在指定的时间点上执行(如延后 5 秒或指定在某个时刻上执行)。下面的代码可以定义一个定时器:

struct time_list mytimer;
// 通过一个辅助函数来初始化定时器数据结构的内部值
init_timer(&my_timer);
// 然后设置自己的值
my_timer.expires = jiffies + delay; /* delay 为定时器超时节拍数,jiffies 是系统全局变量,维护系统发生时钟中断的总次数 */
my_timer.data = 0;                  /* 给定时器处理函数传入 0 值 */
my_timer.function = my_function;    /* 定时器超时时调用的函数 */

my_timer.expires 表示超时时间,它是以节拍为单位的绝对计数值。jiffies 是系统全局变量,维护系统发生时钟中断的总次数。如果当前 jiffies 计数大于 my_timer.expires ,那么 my_timer.function 指向的处理函数就会开始执行。处理函数必须符合下面的函数原型:

void my_timer_function(unsigned long data);

最后,需要激活定时器:

add_timer(&my_timer);

一般来说,定时器都在超时后马上执行,但是也有可能推迟到下一个时钟节拍才能执行,所以不能用定时器来实现任何硬实时任务

上面的方法是延迟一个函数执行,还有一种延迟进程执行的方法是使用 schedule_timeout() 函数,该方法会让需要延迟执行的任务睡眠到指定的延迟时间耗尽后再重新运行。但该方法也不能保证睡眠时间正好等于指定的延迟时间,只能使睡眠时间接近指定的延迟时间。当时间到期后,内核唤醒被延迟的进程并将其重新放回运行队列,用法如下:

/* 将任务设置为可中断睡眠状态 */
set_current_state(TASK_INTERRUPTIBLE);/* 小睡一会,“s” 秒后唤醒 */
schedule_timeout(s * HZ);

唯一的参数为延迟的相对时间,单位为节拍。当任务被设置为 TASK_INTERRUPTIBLE 状态,即可中断状态,那么当任务收到信号时可能被提前唤醒;也可以将任务设置为 TASK_UNINTERRUPTIBLE,这样就不会被信号提前唤醒。既然调用该函数后进程会睡眠,那么这种方法肯定不能在中断上下文或者持有锁的时候使用了。


http://www.ppmy.cn/news/1053761.html

相关文章

HTML <table> 标签

实例 一个简单的 HTML 表格,包含两行两列: <table border="1"><tr><th>Month</th><th>Savings</th></tr><tr><td>January</td><td>$100</td></tr> </table>定义和用法 &l…

Vue2学习笔记のVue组件化编程

目录 Vue组件化编程非单文件组件基本使用几个注意点组件的嵌套VueComponent一个重要的内置关系 单文件组件index.htmlmain.jsApp.vueSchool.vueStudent.vue 各位小伙伴们好呀&#xff0c;不知道上一篇文章你是否有收获&#xff01;这篇是Vue2学习笔记第二篇&#xff0c;也是Vue…

CF 896 C Willem, Chtholly and Seniorious(珂朵莉树模板)

CF 896 C. Willem, Chtholly and Seniorious(珂朵莉树模板) Problem - C - Codeforces 大意&#xff1a;给出一个区间 &#xff0c; 要求进行四种操作 &#xff0c; 区间加 &#xff0c; 区间第k大 &#xff0c; 区间推平 &#xff0c; 区间求和。 珂朵莉树模板题 &#xff…

【C++】unordered_map和unordered_set的使用 及 OJ练习

文章目录 前言1. unordered系列关联式容器2. map、set系列容器和unordered_map、unordered_set系列容器的区别3. unordered_map和unordered_set的使用4. set与unordered_set性能对比5. OJ练习5.1 在长度 2N 的数组中找出重复 N 次的元素思路分析AC代码 5.2 两个数组的交集思路分…

AS中回退git历史版本并删除历史提交记录

当您想把某个版本后的代码删除&#xff0c;回滚到指定的版本。可以使用一下的方法。 一、打开AS中git历史提交窗口 二、选择需要回滚的版本选项&#xff0c;右键弹出菜单。选择Reset Current Branch to Here... 三、选择 Hard 选项 soft&#xff1a;将合并的更改应用到当前分支…

类的加载器及类加载过程

1、类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载Class文件&#xff0c;class文件在文件开头有特定的文件标识。ClassLoader只负责class文件的加载&#xff0c;至于它是否可以运行&#xff0c;则由Execution Engine决定。加载的类信息存放于一块称为方法区的…

取模运算符在数组下标的应用

什么是取模运算符%&#xff1f; 定义&#xff1a; a mod b&#xff0c;设a、b属于正整数且b>0&#xff0c;如果q、r属于正整数满足aq*br&#xff0c;且0≤r<b&#xff0c;则定义&#xff1a; a mod b r 注意&#xff1a;取模运算符两侧的除数和被除数都是整数&#xff…

【golang】go语句执行规则(goroutine)(上)

Don’t communicate by sharing memory;share memory by communicating. 从Go语言编程的角度解释&#xff0c;这句话的意思就是&#xff1a;不要通过共享数据来通讯&#xff0c;恰恰相反&#xff0c;要以通讯的方式共享数据。 进程和线程 进程&#xff0c;描述的就是程序的执…