第八次学习笔记

20211119陈俊积

一、知识点归纳和苏格拉底挑战

硬件定时器

定时器是由时钟源和可编 程计数器组成的硬件设备。时钟源 通常是一个晶体振荡器,会产生周期性电信号,以料青确的频率驱动计数器。使用一个倒计时值对计数器进行编程,每个时钟信号减1。当计 改减为0时,计数器向CPU生成一个定时器中断,将计数值重新加载到计数器中,并重复复倒计时。计数器周期称为定时器刻店度,是系统的基本计时单元。

个人计算机定时器

基于Intel x86的个人计算机有多个定时器:

实时时钟(RTC):

RTC由一个小型备用电池供电。即使在个人计算机关机时,它也能连续运行。它用于实时提供时间和日期信息。当Linux启动时,它使用RTC更新系统时间变量,以与当前时间保持一致。在所有类Unix系统中,时间变量是一个长整数,包含从1970年1月1日起经过的秒数。

可编程间隔定时器(PIT):

PIT是与CPU分离的一个硬件定时器。可对它进行编程,以提供以毫秒为单位的定时器刻度。在所有I/O设备中,PIT可以最高优先级IRQ0中断。PIT定时器中断由Linux内核的定时器中断处理程序来处理,为系统操作提供基本的定时单元,例如进程调度、进程间隔定时器和其他许多定时事件。

多核CPU中的本地定时器:

在多核CPU中,每个核都是一个独立的处理器,它有自己的本地定时器,由CPU时钟驱动。

高分辨率定时器:

大多数电脑都有一个时间戳定时器(TSC),由系统时钟驱动。它的内容可通过64位TSC寄存器读取。由于不同系统主板的时钟频率可能不同,TSC不适合作为实时设备,但它提供纳秒级的定时器分辨率。一些高端个人计算机可能还配备有专用高速定时器,以提供纳秒级定时器分辨率。

CPU操作

每个CPU都有一个程序计数器(PC),也称为指令指针(IP),以及一个标志或状态寄存器(SR)、一个堆栈指针(SP)和几个通用寄存器,当PC指向内存中要执行的下一条指令时,SR包含CPU的当前状态,如操作模式、中断掩码和条件码,SP指向当前堆栈栈顶。
以上各步骤中,由于无效地址、非法指令、越权等原因,可能会出现一个错误状态,称为异常或陷阱。当CPU遇到异常时,它会根据内存中预先安装的指针来执行软件中的异常处理程序。在每条指令执行结束时,CPU会检查挂起的中断。中断是I/O设备或协处理器发送给CPU的外部信号,请求CPU服务。如果挂起的中断请求的状态寄存器已经屏蔽了中断,CPU会忽略中断请求,继续执行下一条指令,否则直接进行中断处理,处理完后恢复指令的正常执行。中断处理和异常处理都在操作系统内核中进行,多数情况下,用户级程序无法访问。

中断处理

外部设备的中断被反馈送到中断控制器的预定义输入行,按优先级对中断输入排序,并将具有最高优先级的中断作为中断请求(IRQ)路由器到CPU。如果状态寄存器屏蔽了中断,CPU会忽略中断请求,使其处于挂起状态,否则,它将直接执行中断处理。对于每个中断,可以编程中断控制器以生成一个唯一编号,叫作中断向量,标识中断源。获取中断向量号后,CPU用它作为内存中中断向量表中的条目索引,条目包含一个指向中断处理程序入口地址的指针来实际处理中断。

时钟服务函数

在几乎所有操作系统(OS)中,操作系统内核都会提供与时钟相关的服务,可以通过系统调用、库函数和用户级命令调用。

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;    /* seconds */
    suseconds_t    tv_usec;   /* microseconds */
};

第二个参数 timezone 已过期,应设置为 NULL。gettimeofday() 函数用于返回当前时间(当前秒的秒和微秒)。settimeofday() 函数用于设置当前时间。在 Unix/Linux 中,时间表示自 1970年1月1日 00:00:00 起经过的秒数。它可以通过库函数 ctime(&time) 转换为日历形式。下面给出了 gettimeofday() 函数和settimeofday() 函数的示例。

gettimeofday 系统调用
#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
#include<time.h>
struct timeval t;
int main()
{
 gettimeofday(&t,NULL);
 printf("sec=%ld usec=%ld\n",t.tv_sec,t.tv_usec);
 printf((char *)ctime(&t.tv_sec));
}
settimeofday 系统调用
#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));
}

time 系统调用

Time_t time(time_t *t)

以秒为单位返回当前时间,若参数t不是NULL,则会将时间存储在t指向的内存中。time系统调用具有一定局限性,只能提供以秒为单位的分辨率,而不是以微秒为单位。

times 系统调用

times 系统调用

clock_t times(struct tms *bus);

可用于获取某进程的具体执行时间。它将进程时间存储在 struct tms buf 中,即:


struct tms{
    clock_t tms_utime;    // user mode time
    clock_t tms_stime;    // system mode time
    clock_t tms_cutime;   // user time of children
    clock_t tms_cstime;   // system time of children
}

以时钟计时单元报告所有时间。这可以为分析某个正在执行的进程提供信息,包括其子进程的时间(如有)。

time 和 date 命令

  • date:打印或设置系统日期和时间。
  • time:报告进程在用户模式和系统模式下的执行时间和总时间。
  • hwclock:查询并设置硬件时钟(RTC),也可以通过 BIOS 来完成。

苏格拉底挑战

在这里插入图片描述
在这里插入图片描述

二、问题与解决思路

强制转换类型

警告说明传递给printf函数的参数不是格式化字符串,而是一个指向字符串的指针。这种写法会导致潜在的安全问题,因为如果字符串中包含格式化占位符,那么printf函数可能会按照占位符的意图解析其他参数。这可能导致栈缓冲区溢出等严重问题。
在这里插入图片描述
解决方法:
将printf函数的第一个参数改为格式化字符串,用%s占位符表示要输出的字符串。这样就可以避免潜在的安全问题。
在没影响的情况下可以无视。

三、实践内容与截图

gettimeofday 系统调用

#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
#include<time.h>
struct timeval t;
int main()
{
 gettimeofday(&t,NULL);
 printf("sec=%ld usec=%ld\n",t.tv_sec,t.tv_usec);
 printf((char *)ctime(&t.tv_sec));
}

在这里插入图片描述

settimeofday 系统调用

#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));
}

在这里插入图片描述

time 系统调用

#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);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值