Ⅰ知识点归纳
一、硬件定时器
定时器是由时钟源和可编程计数器组成的硬件设备。时钟源通常是一个晶体振荡器,会产生周期性电信号,以精确的频率驱动计数器。
硬件定时器能够按照一定的频率周期性的有规律的给CPU发送中断信号,发送中断的频率(周期)可以通过软件编程来设置,硬件定时器产生的中断信号可以称之为时钟中断。
二、个人计算机定时器
(1)实时时钟(RTC):RTC由一个小型备用电池供电。即使在个人计算机关机时,它也能连续运行。它用于实时提供时间和日期信息。当Linux启动时,它使用RTC更新系统时间变量,以与当前时间保持一致。在所有类Unix 系统中,时间变量是一个长整数,包含从1970年1月1日起经过的秒数。
(2)可编程间隔定时器(PIT)(Wang 2015)∶PIT是与CPU分离的一个硬件定时器。可对它进行编程,以提供以毫秒为单位的定时器刻度。在所有I/O设备中,PIT 可以最高优先级 IRQ0中断。PIT定时器中断由Linux 内核的定时器中断处理程序来处理,为系统操作提供基本的定时单元,例如进程调度、进程间隔定时器和其他许多定时事件。
(3)多核CPU 中的本地定时器(Intel 1997;Wang 2015))∶在多核CPU中,每个核都是一个独立的处理器,它有自己的本地定时器,由 CPU时钟驱动。
(4)高分辨率定时器∶大多数电脑都有一个时间戳定时器(TSC)由系统时钟驱动。它的内容可通过64 位 TSC寄存器读取。由于不同系统主板的时钟频率可能不同,TSC不适合作为实时设备,但它可提供纳秒级的定时器分辨率。—些高端个人计算机可能还配备有专用高速定时器,以提供纳秒级定时器分辨率。
三、CPU操作
每个CPU都有一个程序计数器(PC),也称为指令指针(IP),以及一个标志或状态寄存器(SR)、一个堆栈指针(SP)和几个通用寄存器,当 PC指向内存中要执行的下一条指令时,SR包含 CPU 的当前状态,如操作模式、中断掩码和条件码,SP指向当前堆栈栈顶。CPU操作可通过无限循环进行建模。
while (power-on){
(1). fetch instruction:load*PC as instruction,increment PC to point to the
next instruction in memory;
(2). decode instruction: interpret the instruction's operation code and
generate operandis;
(3). execute instruction: perform operation on operands,write results to
memory if needed; execution may use the stack,implicitly change PC, etC.
(4) . check for pending interrupts; may handle interrupts;
}
四、间隔定时器
参考博客:https://blog.csdn.net/qq_41694204/article/details/82893585
间隔定时器的接口如下:
#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
结构定义:
struct itimerval {
struct timeval it_interval; /* next value :间隔时间*/
struct timeval it_value; /* current value:到期时间*/
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
每个进程中同一种定时器只能使用一次。
该系统调用在POSIX.1-2001中定义了,但在POSIX.1-2008中已被废弃。所以建议使用POSIX定时器API(timer_gettime, timer_settime)代替。
函数alarm本质上设置的是低精确、非重载的ITIMER_REAL类定时器,它只能精确到秒,并且每次设置只能产生一次定时。函数setitimer 设置的定时器则不同,它们不但可以计时到微妙(理论上),还能自动循环定时。在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器。
Ⅱ问题与解决思路
问题:
Linux里如何用C编程实现gettimeofday系统调用
解决思路:
代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
struct timeval t;
int main()
{
gettimeofday(&t,NULL);
printf("sec=%ld usec=%d\n", t.tv_sec, t.tv_usec);
printf((char *)ctime(&t.tv_sec));
}
截图:
Ⅲ实践内容与截图,代码链接
1.man -k time
2.time系统调用
代码:
#include<stdio.h>
#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);
}
截图:
3.间隔定时器
代码:
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
int count = 0;
struct itimerval t;
time_t start,end ;
void timer_handler(int sig){
end =time(NULL);
printf("timer_handler : signal %d count=%d , diff: %ld \n",sig, ++count,end -start);
start = end;
if( count >= 8){
printf("cancel timer \n");
t.it_value.tv_sec = 0 ;
t.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &t , NULL);
}
}
int main(){
struct itimerval timer ;
signal (SIGVTALRM ,timer_handler);
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 100000;
//every 1s afterward
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
// start a virtual itimer
start = time(NULL);
setitimer( ITIMER_VIRTUAL , &timer ,NULL );
printf("press Ctrl + C to terminate \n");
while(1);
}