Linux系统编程第五章学习笔记
前言
本章介绍了定时器和定时器服务。它解释了硬件定时器的原理以及基于Intel x86的PC中的硬件定时器。它涵盖了CPU操作和中断处理。它描述了与定时器相关的系统调用、库函数和Linux中用于定时器服务的命令。它讨论了进程间隔定时器、定时器生成的信号,并通过示例演示了进程间隔定时器。编程项目是在多任务系统中实现定时器、定时器中断和间隔定时器。多任务系统作为Linux进程运行,充当Linux进程内并发任务的虚拟CPU。 Linux进程的实时模式间隔定时器被编程周期性生成SIGALRM信号,它充当虚拟CPU的定时器中断处理程序,该项目是为了让读者通过一个定时器队列来实现任务的间隔定时器。它还允许读者使用Linux信号掩码来实现临界区,以防止任务和中断处理程序之间的竞争条件。
1 硬件定时器
定时器是一种硬件设备,包括一个时钟源和一个可编程计数器。时钟源通常是晶体振荡器,它会生成周期性的电信号,以精确的频率驱动计数器。计数器被编程为一个倒计数值,每个时钟信号减1。当计数减到0时,计数器会向CPU生成一个定时器中断,然后重新加载计数值到计数器并再次开始倒计数。计数器的周期称为定时器滴答,是系统的基本时间单位。
2 PC定时器
基于Intel x86的PC具有多个定时器(Bovet和Cesati 2005)。
-
实时时钟(RTC):RTC由小型备用电池供电,即使PC的电源关闭,它也会持续运行。它用于保持实时时间以提供时间和日期信息。当Linux启动时,它使用RTC来更新系统时间变量以跟踪当前时间。在所有类Unix系统中,时间变量是一个长整数,包含自1970年1月1日开始以来经过的秒数。
-
可编程间隔定时器(PIT)(Wang 2015):PIT是与CPU分离的硬件定时器。它可以被编程以毫秒为分辨率提供定时器滴答。在所有I/O设备中,PIT以最高优先级IRQ0进行中断。PIT定时器中断由Linux内核的定时器中断处理程序处理,以提供系统操作的基本时间单位,如进程调度、进程间隔定时器和众多其他定时事件。
-
多核CPU中的本地定时器(Intel 1997; Wang 2015):在多核CPU中,每个核都是独立的处理器,具有由CPU时钟驱动的本地定时器。
-
高分辨率定时器:大多数PC具有一个时间戳计数器(TSC),由系统时钟驱动。其内容可以通过64位TSC寄存器读取。
3 CPU操作
每个CPU都有一个程序计数器(PC),也被称为指令指针(IP),一个标志或状态寄存器(SR),一个堆栈指针(SP)和几个通用寄存器,其中PC指向内存中将要执行的下一条指令,SR包含CPU的当前状态,例如操作模式、中断屏蔽和条件码,SP指向当前堆栈的顶部。堆栈是CPU用于特殊操作的内存区域,如push、pop、call和return等。 CPU的操作可以通过一个无限循环来建模。
while (开机){
(1). 取指令:加载*PC作为指令,将PC递增以指向内存中的下一条指令;
(2). 解码指令:解释指令的操作代码并生成操作数;
(3). 执行指令:对操作数执行操作,如果需要,将结果写入内存; 执行可能使用堆栈,隐式更改PC等。
(4). 检查待处理的中断; 可能会处理中断;
}
在上述每个步骤中,由于无效地址、非法指令、特权违规等,可能会发生错误条件,称为异常或陷阱。当CPU遇到异常时,它会遵循内存中预先安装的指针来执行软件中的异常处理程序。在每个指令执行结束时,CPU会检查待处理的中断。中断是来自I/O设备或协处理器的外部信号,请求CPU服务。如果存在待处理的中断请求但CPU不处于接受中断的状态,即其状态寄存器屏蔽了中断,CPU将忽略中断请求并继续执行下一条指令。否则,它将将执行转向中断处理。在中断处理结束后,它将恢复正常执行指令。中断处理和异常处理在操作系统内核中处理。在很大程度上,它们对用户级程序是不可访问的,但它们是理解操作系统中的定时器服务和信号的关键,如Linux等。
4 中断处理
来自外部设备(如定时器)的中断被馈送到中断控制器的预定义输入线(Intel 1990; Wang 2015),中断控制器会为中断输入排序并将具有最高优先级的中断路由为中断请求(IRQ)发送到CPU。在每条指令执行结束时,如果CPU不处于接受中断的状态,即在CPU状态寄存器中屏蔽了中断,它将忽略中断请求,保持中断挂起,并继续执行下一条指令。如果CPU处于接受中断的状态,即中断未被屏蔽,CPU将改变其正常执行顺序以执行中断处理。对于每个中断,中断控制器可以被编程为生成一个唯一的编号,称为中断向量,用于标识中断源。在获得中断向量编号后,CPU将其用作内存中中断向量表(AMD64 2011)中的入口地址的索引,该表包含中断处理程序的入口地址的指针,实际上处理中断。中断处理完成后,CPU将恢复正常执行指令。
5 时间服务函数
在几乎每个操作系统(OS)中,OS内核都提供了各种与时间相关的服务。时间服务可以通过系统调用、库函数和用户级命令来调用。在本节中,我们将介绍Linux的一些基本时间服务函数。
5.1 Gettimeofday-Settimeofday
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
这些是Linux内核的系统调用。第一个参数tv指向一个timeval结构。
struct timeval {
time_t tv_sec; /* 秒 */
suseconds_t tv_usec; /* 微秒 */
};
第二个参数timezone已经过时,应该设置为NULL。gettimeofday()函数返回当前时间,包括当前秒数和当前秒内的微秒数。settimeofday()函数用于设置当前时间。在Unix/Linux中,时间用从1970年1月1日00:00:00以来经过的秒数来表示。可以使用库函数ctime(&time)将其转换为日历形式。以下示例演示了gettimeofday()和settimeofday()的使用。
(1). Gettimeofday系统调用
示例 5.1
通过gettimeofday()获取系统时间
/********* gettimeofday.c 文件 *********/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
struct timeval t;
int main()
{
gettimeofday(&t, NULL);
printf("秒数=%ld 微秒=%d\n", t.tv_sec, t.tv_usec);
printf((char *)ctime(&t.tv_sec));
return 0;
}
这个程序应该显示当前时间的秒数、微秒数,以及当前日期和时间的日历形式,如下所示:
秒数=1515624303 微秒=860772
Wed Jan 10 14:45:03 2018
(2). Settimeofday系统调用
示例 5.2
通过settimeofday()设置系统时间
/********* settimeofday.c 文件 *********/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
struct timeval t;
int main()
{
int r;
t.tv_sec = 123456789;
t.tv_usec= 0;
r = settimeofday(&t, NULL);
if (!r){
printf(“settimeofday() failed\n”);
exit(1);
}
gettimeofday(&t, NULL);
printf("sec=%ld usec=%ld\n", t.tv_sec, t.tv_usec);
printf(“%s”, ctime(&t.tv_sec)); // show time in calendar form
这个程序的输出应该类似于:
sec=123456789 usec=862
Thu Nov 29 13:33:09 1973
根据打印的日期和年份(1973),似乎settimeofday()
操作已成功。然而,在某些Linux系统中,例如Ubuntu 15.10,效果可能仅是临时的。如果读者再次运行gettimeofday
程序,它将显示Linux已将系统时间更改回正确的实时时间。这表明Linux内核具有使用实时时钟(和其他时间同步协议)来校正系统时间与实际时间之间的任何偏差的能力。
5.2 时间系统调用
示例 5.3
时间系统调用
time_t time(time_t *t);
返回当前时间(以秒为单位)。如果参数 t
不是 NULL
,它还将时间存储在 t
指向的内存中。时间系统调用的限制是它仅以秒为分辨率,而不是微秒。此示例演示如何获取系统时间(以秒为单位)。
/************ time.c 文件 ***********/
#include <stdio.h>
#include <time.h>
time_t start, end;
int main()
{
int i;
start = time(NULL);
printf("start=%ld\n", start);
for (i = 0; i < 123456789; i++); // 延迟以模拟计算
end = time(NULL);
printf("end=%ld time=%ld\n", end, end - start);
}
输出应该打印出开始时间、结束时间以及从开始到结束的秒数。
5.3 times 系统调用
clock_t times(struct tms *buf);
可以用来获取进程的详细执行时间。它将进程时间存储在一个 struct tms
结构中,其中包括用户模式时间、系统模式时间、子进程的用户时间和子进程的系统时间。所有报告的时间都以时钟滴答为单位,用于分析正在执行的进程,包括其子进程(如果有的话)的时间。
5.4 时间和日期命令
date
:打印或设置系统日期和时间。time
:报告用户模式、系统模式和总时间的进程执行时间。hwclock
:查询和设置硬件时钟(RTC),也可以通过BIOS进行设置。
苏格拉底挑战
学习定时器与时间服务
当然,我会以苏格拉底的方式提出问题来帮助您学习定时器与时间服务知识点。让我们开始:
问题1:为什么计算机系统需要定时器和时间服务?
时间同步和时钟管理:计算机系统中有多个硬件和软件组件需要协调工作,确保它们在正确的时间执行。定时器和时间服务帮助系统保持时间同步,确保各个组件按照统一的时间标准工作,这对于文件时间戳、日志记录、网络通信等方面都至关重要。
任务调度:操作系统需要管理多个进程或线程,以确保它们在合适的时间片内执行。定时器用于触发任务切换,确保每个任务都有公平的时间片并能够得到执行。
性能分析和故障排查:时间服务可以帮助开发人员分析性能问题和排查故障。通过时间戳和性能数据的记录,开发人员可以了解程序的执行时间和资源利用情况,从而找到性能瓶颈和错误。
实时系统:在实时系统中,任务必须在特定时间内完成,否则可能会引发严重的问题。定时器和时间服务确保实时任务按时执行,例如飞行控制系统、医疗设备和工业自动化系统。
安全性:时间服务还可以用于安全目的。例如,安全协议和加密算法通常依赖于时间来生成安全随机数和验证证书有效性。
数据一致性:在分布式系统中,时间戳常用于确定事件的发生顺序,以确保数据一致性和事务的正确执行。
总之,定时器和时间服务在计算机系统中扮演着关键的角色,不仅用于时间管理,还对任务调度、性能分析、实时系统、安全性和数据一致性等方面有着广泛的应用。这些服务有助于确保计算机系统的正常运行、性能优化和数据完整性。
非常好的回答!您已经详细解释了计算机系统需要定时器和时间服务的多个方面的原因。接下来,让我们深入了解定时器和时间服务的工作原理:
问题2:定时器是如何工作的,它们是如何生成时间事件的?
时间基准:定时器需要一个时间基准,通常是计算机的系统时钟或定时器硬件中的时钟。这个时钟以一定的速率发出脉冲或时钟信号,用于测量时间的流逝。
计时设置:在使用定时器之前,需要配置定时器以生成所需的时间事件。这通常包括设置一个初始计数值,该值与时间基准的时钟信号相结合,以确定何时触发事件。计时器可能还需要其他参数,如触发条件和操作。
计数和比较:定时器开始计数,递减计数值或递增计数值,具体取决于计时器的类型。同时,它持续地比较计数值与预先设置的比较值。当计数值等于或超过比较值时,定时器触发一个时间事件。
事件触发:一旦计数值满足触发条件,定时器会触发时间事件。这可以通过产生中断请求、执行特定操作、发送信号或调用回调函数来实现,具体取决于定时器的类型和用途。
重置或重新配置:在触发时间事件后,定时器通常需要被重置或重新配置,以便继续生成时间事件。这可能涉及到重新设置计数值、更改触发条件或进行其他操作。
定时器的工作方式和性质可以根据用途和实现方式而有所不同。有多种类型的定时器,包括硬件定时器、软件定时器和实时时钟(RTC)。硬件定时器通常由计算机的硬件支持,例如CPU中的计时器,用于精确测量时间间隔和触发事件。软件定时器则是通过编程实现的,通常在操作系统或应用程序级别使用。实时时钟用于维护日期和时间信息,例如在操作系统中记录文件的创建和修改时间。
总之,定时器是计算机系统中用于生成时间事件的重要组件,其工作原理基于时间基准、计时设置、计数和比较,以及事件触发。不同类型的定时器在不同应用场景中都有重要作用。
非常清晰和详尽的解释!现在让我们继续:
问题3:在计算机系统中,时间服务是如何提供和维护精确的时间信息的?
系统时钟(System Clock):计算机系统通常有一个系统时钟,它是硬件计时器,以恒定的速率发出时钟信号。这个时钟信号用于测量时间的流逝,并提供一个基本时间标准,通常以赫兹(Hz)为单位,例如1秒内发出的脉冲次数。系统时钟通常提供计算机系统的时间基准。
操作系统时间服务:操作系统通常提供了一系列时间服务,用于管理系统时间。这包括获取当前时间、设置系统时间、定时器管理、时间戳生成和时间同步等功能。操作系统通过系统调用或API提供这些服务,允许应用程序和其他系统组件访问和操作时间信息。
网络时间协议(NTP):NTP是一种用于在计算机网络中同步时间的协议。它允许计算机系统从时间服务器获取准确的时间信息,并将系统时间与网络时间同步。NTP协议通常用于保持计算机系统之间的时间同步,特别是在分布式系统和网络环境中。
硬件时钟模块:某些计算机系统和服务器具有专门的硬件时钟模块,如实时时钟(RTC)。这些模块通常包括电池支持,以确保即使在系统关机时也能继续保持时间信息,以防止时间丢失或重新设置。
GPS 时间信号:在需要极高精度时间的应用中,例如科学研究和精确的时间戳记录,可以使用全球定位系统(GPS)来获取高度准确的时间信号。GPS接收器可以接收卫星发出的时间信号,从而提供精确的时间信息。
振荡器和晶振:计算机硬件中的振荡器和晶振用于提供稳定的时钟信号。这些元件通常用于计算机主板上,以确保系统时钟的稳定性和精确性。
维护精确时间信息对于各种应用非常重要,例如网络通信、数据同步、安全协议、日志记录等。不同应用需要不同级别的时间精确度,因此可以根据需求选择合适的时间服务和硬件组件来满足要求。
非常出色的解答!您详细介绍了在计算机系统中提供和维护精确的时间信息所使用的不同方法和组件。现在让我们继续:
问题4:在实际应用中,可以举例说明定时器和时间服务的具体用途吗?
实时操作系统:在实时嵌入式系统中,定时器用于确保任务按时完成。例如,汽车的发动机控制系统需要确保点火、燃油喷射等任务按时执行,以确保引擎正常运行。
网络通信:网络设备使用定时器来处理各种网络协议,例如TCP连接的超时和重传。此外,网络时间协议(NTP)用于同步网络设备的时间,以确保数据包的时间戳正确。
文件系统:在文件系统中,文件的创建、修改和访问时间戳是通过定时器来生成的。这有助于跟踪文件的属性和维护文件元数据。
性能分析:开发人员可以使用定时器来测量代码块的执行时间,以进行性能分析和性能优化。这有助于识别应用程序中的瓶颈和效率问题。
日志记录:在日志记录中,时间戳通常用于标记事件的发生时间。这有助于追踪系统的操作、故障排查和安全审计。
安全协议:安全协议和加密算法通常依赖于时间来生成随机数和验证证书的有效性。时间戳和时间服务在加密和安全通信中起着关键作用。
分布式系统:在分布式系统中,时间戳用于确定事件的发生顺序,以确保数据一致性和事务的正确执行。一致性协议如Paxos和Raft使用时间戳来协调分布式节点的行为。
科学研究:在科学实验中,精确的时间测量是至关重要的。例如,天文学家使用时间服务来记录星系的观测时间,以研究天体运动。
非常出色的示例!您提供了各种实际应用场景,清晰地说明了定时器和时间服务在计算机系统中的重要性。这些例子涵盖了多个领域,从操作系统和网络通信到日志记录和科学研究,都显示了时间管理的广泛应用。如果您有任何进一步的问题或需要更多的信息,都请告诉我。
根据您对定时器与时间服务知识点的回答和交互,看起来您对这一主题有了很好的理解。您已经提供了详细的回答,并且能够解释定时器和时间服务的工作原理以及它们在计算机系统中的应用。如果您对这个主题还有任何疑问或需要进一步的信息,都请随时向我提问。我将很乐意帮助您进一步深入了解。
您的回答表现出了对定时器与时间服务知识点的良好理解。您提供了清晰和详尽的解释,涵盖了该主题的各个方面,包括定时器的工作原理、时间服务的提供方式以及实际应用场景。您还使用了丰富的示例来说明这些概念在实际中的重要性。总的来说,您的回答表现出了对该知识点的深刻理解和能力以清晰方式传达相关信息。如果您希望深入了解或有进一步的问题,都请随时提问,我将很愿意为您提供更多帮助。