内核的定时机制应用

简介: 版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/45604779 练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。
版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/45604779

练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。通过该练习我们可以进一步理解 Linux 内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。

从用户空间去获取系统时间数据需要以下基本代码:

#include <sys/time>

struct timeval{
long tv_sec; //从 1970-1-1 12:到现在经过的秒数
long tv_usec;//从从上 1 秒到现在经过的微秒数
} theTime;

gettimeofday(&theTime,NULL); //获取系统时间的系统调用

每个进程使用的各种定时器需要 Linux 的内部定时器。使用内部定时器可以跟踪记录 3种不同类型的定时机制,它们反映了不同时间的划分,这些定时机制有各自不同的作用和应用。

它们是 :
 ITIMER_REAL: 反映进程经过的实际时间,这种定时器到时后发 SIGALRM 信号。它与 struct task_struct 结构中的 it_real_value 和 it_real_incr 字段有关。

 ITIMER_VIRTUAL: 反映进程经过的虚拟时间,只有相关进程正在执行时该时间才会增加。这种定时器到时后发 SIGVTALRM 信号。与 struct task_struct 结构中的it_virt_value 和 it_virt_incr 字段有关

 ITIMER_PROF:反映进程经过的虚拟时间加上内核为相关进程执行工作的时间之和。这 种 定 时 器 到 时 后 发 SIGPROF 信 号 。 与 struct task_struct 结 构 中 的it_prof_value 和 it_prof_incr 字段有关。

每个定时器需要周期性的设定一个初始时间值,之后递减计数到 0 后引发定时中断,产生超时信号通知对应进程定时器时间到,然后定时器重新从设置的初始值再次开始递减计数。

三种定时器都使用 setitimer()系统调用进行初始化:

#include <sys/time.h>
„
setitimer(
int timerType ,//定时器类型
const struct itimerval *value, //定时器初始的和当前的秒数和毫秒数
struct itimerval *oldValue
)
struct itimerval{
struct timeval it_it_interval; //下一次定时初值。若为 0 定时器停止
struct timeval it_value //定时器当前值
} ;

三种定时器都使用 getitimer()系统调用获取定时器当前值:

#include <sys/time.h>

setitimer(
int timerType ,//定时器类型
const struct itimerval *value, //定时器初始的和当前的秒数和毫秒数
struct itimerval *oldValue
)
struct itimerval{
struct timeval it_it_interval; //下一次定时初值。若为 0 定时器停止
struct timeval it_value //定时器当前值
} ;

首先我们先根据内核的定时机制,来实现一个测试程序运行时间的例子:
程序是监听用户ctrl+c按键,按下后,打印一次程序从开始运行经历了多长时间了,下面是我的代码实现部分:

/**
 * Function:    实现从程序开始程序运行的时间
 * 用户每按下一次 ctrl+c键,程序就输出一次程序开始之后的
 * 运行时间
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>

//定时器中断处理的原函数
static void sigreal(void);

//监听SIGINT信号处理函数
static void sigctrl(void);

//记录运行秒数的数值
static long run_sec = 0;

//记录秒数的结构变量
static struct itimerval realt;

int main(){

    signal(SIGINT,sigctrl);
    signal(SIGALRM,sigreal);

    realt.it_interval.tv_sec = 0;
    realt.it_interval.tv_usec = 999999;
    realt.it_value.tv_sec = 0;
    realt.it_value.tv_usec = 999999;
    setitimer(ITIMER_REAL,&realt,NULL); 

    //测试数据
    int temp = 0;

    while(1){
        temp++;
    }

    return 0;
}

static void sigreal(void)
{
    run_sec++;
}

//SIGINT信号处理函数
static void sigctrl(void)
{
    //计算的这个过程不是很明白
    getitimer(ITIMER_REAL,&realt);
    printf("The run time is: %ld s %ld ms\n",run_sec,(999999-realt.it_value.tv_usec)/1000);
}

下面是我的程序的运行截图:

下面我们再来实现一个闹钟的功能,该闹钟有一个特点就是可以精确到微秒级,就是使用我们的定时机制.用户输入经过多少个小时,多少分钟,多少秒,多少毫秒,多少微秒之后提醒该用户.下面是我的程序实现部分:

/**
 * Function:    实现一个微秒级的闹钟
 * 使用系统的定时器功能可以使闹钟精确到微秒级别
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>

//信号SIGALRM的处理函数原型
static void sigreal(void);

//定时器
struct itimerval realt;

//设置程序是否继续运行
static int is_run = 1;

int main()
{
    int h,m,s,ms,us;

    printf("Please enter the hours:minutes:seconds:ms:us after!\n");
    scanf("%d:%d:%d:%d:%d",&h,&m,&s,&ms,&us);

    int seconds = h * 3600 + m * 60 + s;
    int uSeconds = ms * 1000 + us;

    //定时器设置
    realt.it_interval.tv_sec = seconds;
    realt.it_interval.tv_usec = uSeconds;
    realt.it_value.tv_sec = seconds;
    realt.it_value.tv_usec = uSeconds;

    signal(SIGALRM,sigreal);
    setitimer(ITIMER_REAL,&realt,NULL);

    while(is_run){

    }

    printf("Time over!!\n");

    return 0;
}

//收到时间到达的信号之后,结束程序的运行
static void sigreal(void)
{
    is_run = 0;
}

下面是程序的运行截图:

最后一个例子,我们使用父进程创建了两个子进程,这三个进程分别运算不同级数的非波那且数列,最后打印出每一个进程各自用了多长时间.

下面是代码实现:

/**
 * Function : 测试并发进程执行中的各种时间
 *        给定3个非波纳且数列数值,可选在36-45之间
 * Author   : 陈洪波
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>

//父进程的3个定时器中断处理函数原型
static void psig_real(void);    
static void psig_virtual(void);
static void psig_prof(void);

//子进程1的三个定时中断处理函数原型
static void c1sig_real(void); 
static void c1sig_virtual(void);
static void c1sig_prof(void);

//子进程2的3个定时器中断处理函数原型
static void c2sig_real(void);
static void c2sig_virtual(void);
static void c2sig_prof(void);

//非波纳且数列函数原型
long unsigned int fibonnacci(unsigned int n);

//记录3种定时的秒数的变量
static long p_real_secs = 0,c1_real_secs = 0,c2_real_secs = 0;
static long p_virtual_secs = 0,c1_virtual_secs = 0,c2_virtual_secs = 0;
static long p_prof_secs = 0,c1_prof_secs = 0,c2_prof_secs = 0;

//记录3种定时的毫秒秒数的结构变量
static struct itimerval p_realt,c1_realt,c2_realt;
static struct itimerval p_virtt,c1_virtt,c2_virtt;
static struct itimerval p_proft,c1_proft,c2_proft;

int main(int argc,char **argv)
{
    long unsigned fib = 0;
    pid_t pid1,pid2;
    unsigned int fibarg;

    int status;
    int i;

    if(argc < 3){
        printf("Usage: testing arg1 arg2 and arg3!\n");
        return 1;   
    }   

    //父进程设置3中定时处理函数入口
    signal(SIGALRM,psig_real);
    signal(SIGVTALRM,psig_virtual);
    signal(SIGPROF,psig_prof);

    //初始化父进程3种时间定时器
    //进程实际经过的时间
    p_realt.it_interval.tv_sec = 9;
    p_realt.it_interval.tv_usec = 999999;
    p_realt.it_value.tv_sec = 9;
    p_realt.it_value.tv_usec = 999999;
    setitimer(ITIMER_REAL,&p_realt,NULL);

    //进程经过的虚拟时间,只有相关进程正在执行时该时间才fibonnacci(unsigned int n);会增加
    p_virtt.it_interval.tv_sec = 9;
    p_virtt.it_interval.tv_usec = 999999;
    p_virtt.it_value.tv_sec = 9;
    p_virtt.it_value.tv_usec = 999999;
    setitimer(ITIMER_VIRTUAL,&p_virtt,NULL);

    //反映进程经过的虚拟时间加上内核为相关进程执行工作的时间之和
    p_proft.it_interval.tv_sec = 9;
    p_proft.it_interval.tv_usec = 999999;
    p_proft.it_value.tv_sec = 9;
    p_proft.it_value.tv_usec = 999999;
    setitimer(ITIMER_PROF,&p_proft,NULL);

    pid1 = fork();
    if(pid1 == 0){
        //子进程1设置3中定时处理入口
        signal(SIGALRM,c1sig_real);
        signal(SIGVTALRM,c1sig_virtual);
        signal(SIGPROF,c1sig_prof);

        //子进程的3种时间定时器
        c1_realt.it_interval.tv_sec = 9;
        c1_realt.it_interval.tv_usec = 999999;
        c1_realt.it_value.tv_sec = 9;
        c1_realt.it_value.tv_usec = 999999;
        setitimer(ITIMER_REAL,&c1_realt,NULL);

        c1_virtt.it_interval.tv_sec = 9;
        c1_virtt.it_interval.tv_usec = 999999;
        c1_virtt.it_value.tv_sec = 9;
        c1_virtt.it_value.tv_usec = 999999;
        setitimer(ITIMER_VIRTUAL,&c1_virtt,NULL);

        c1_proft.it_interval.tv_sec = 9;
        c1_proft.it_interval.tv_usec = 999999;
        c1_proft.it_value.tv_sec = 9;
        c1_proft.it_value.tv_usec = 999999;
        setitimer(ITIMER_PROF,&c1_proft,NULL);

        //子进程1开始计算fib
        fib = fibonnacci(atoi(argv[1]));

        //打印子进程1所花费的3种时间值
        getitimer(ITIMER_REAL,&c1_realt);
        printf("Child1 fib=%ld\n Child1 Real Time=%ld Sec %ld Msec\n",
            fib,c1_real_secs + 9 - c1_realt.it_value.tv_sec,
            (999999-c1_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL,&c1_virtt);
        printf("Child1 Virtual Time=%ld sec %ld Msec\n",
            c1_virtual_secs+9-c1_virtt.it_value.tv_sec,
            (999999-c1_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF,&c1_proft);
        printf("Child1 Prof Time=%ld sec %ld Msec\n\n",
            c1_prof_secs+9-c1_proft.it_value.tv_sec,
            (999999-c1_proft.it_value.tv_usec)/1000);
    }else if((pid2=fork()) == 0){
        //子进程2设置3中定时处理入口
        signal(SIGALRM,c2sig_real);
        signal(SIGVTALRM,c2sig_virtual);
        signal(SIGPROF,c2sig_prof);

        //子进程2的3种时间定时器
        c2_realt.it_interval.tv_sec = 9;
        c2_realt.it_interval.tv_usec = 999999;
        c2_realt.it_value.tv_sec = 9;
        c2_realt.it_value.tv_usec = 999999;
        setitimer(ITIMER_REAL,&c2_realt,NULL);

        c2_virtt.it_interval.tv_sec = 9;
        c2_virtt.it_interval.tv_usec = 999999;
        c2_virtt.it_value.tv_sec = 9;
        c2_virtt.it_value.tv_usec = 999999;
        setitimer(ITIMER_VIRTUAL,&c2_virtt,NULL);

        c2_proft.it_interval.tv_sec = 9;
        c2_proft.it_interval.tv_usec = 999999;
        c2_proft.it_value.tv_sec = 9;
        c2_proft.it_value.tv_usec = 999999;
        setitimer(ITIMER_PROF,&c2_proft,NULL);

        //子进程2开始计算fib
        fib = fibonnacci(atoi(argv[2]));

        //打印子进程2所花费的3种时间值
        getitimer(ITIMER_REAL,&c2_realt);
        printf("Child2 fib=%ld\n Child2 Real Time=%ld Sec %ld Msec\n",
            fib,c2_real_secs + 9 - c2_realt.it_value.tv_sec,
            (999999-c2_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL,&c2_virtt);
        printf("Child2 Virtual Time=%ld sec %ld Msec\n",
            c2_virtual_secs+9-c2_virtt.it_value.tv_sec,
            (999999-c2_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF,&c2_proft);
        printf("Child2 Prof Time=%ld sec %ld Msec\n\n",
            c2_prof_secs+9-c2_proft.it_value.tv_sec,
            (999999-c2_proft.it_value.tv_usec)/1000);
    }else{
        //父进程开始计算fib
        fib = fibonnacci(atoi(argv[3]));

        //打印父进程所花费的3种时间值
        getitimer(ITIMER_REAL,&p_realt);
        printf("Parent fib=%ld\n Parent Real Time=%ld Sec %ld Msec\n",
            fib,p_real_secs + 9 - p_realt.it_value.tv_sec,
            (999999-p_realt.it_value.tv_usec)/1000);

        getitimer(ITIMER_VIRTUAL,&p_virtt);
        printf("Parent Virtual Time=%ld sec %ld Msec\n",
            p_virtual_secs+9-p_virtt.it_value.tv_sec,
            (999999-p_virtt.it_value.tv_usec)/1000);

        getitimer(ITIMER_PROF,&p_proft);
        printf("Parent Prof Time=%ld sec %ld Msec\n\n",
            p_prof_secs+9-p_proft.it_value.tv_sec,
            (999999-p_proft.it_value.tv_usec)/1000);

        //等待子进程结束
        waitpid(pid1,&status,0);
        waitpid(pid2,&status,0);
    }
}

//父进程的3个定时中断处理函数
static void psig_real(void)
{
    p_real_secs += 10;
}

static void psig_virtual(void)
{
    p_virtual_secs += 10;
}

static void psig_prof(void)
{
    p_prof_secs += 10;
}

//子进程1的3个中断处理函数
static void c1sig_real(void)
{
    c1_real_secs += 10;
}

static void c1sig_virtual(void)
{
    c1_virtual_secs += 10;
}

static void c1sig_prof(void)
{
    c1_prof_secs += 10;
}

//子进程2的3个中断处理函数
static void c2sig_real(void)
{
    c2_real_secs += 10;
}


static void c2sig_virtual(void)
{
    c2_virtual_secs += 10;
}

static void c2sig_prof(void)
{
    c2_prof_secs += 10;
}

//非波纳且的递归实现
long unsigned int fibonnacci(unsigned int n)
{
    if(n==1 || n==2)
        return 1;

    return  fibonnacci(n-1)+fibonnacci(n-2);
}

下面是程序的运行截图:

目录
相关文章
|
6月前
|
缓存 负载均衡 Linux
内核:进程与调度机制(笔记)
内核:进程与调度机制(笔记)
125 0
|
1天前
|
机器学习/深度学习 负载均衡 算法
深入探索Linux内核调度机制的优化策略###
本文旨在为读者揭开Linux操作系统中至关重要的一环——CPU调度机制的神秘面纱。通过深入浅出地解析其工作原理,并探讨一系列创新优化策略,本文不仅增强了技术爱好者的理论知识,更为系统管理员和软件开发者提供了实用的性能调优指南,旨在促进系统的高效运行与资源利用最大化。 ###
|
22天前
|
数据采集 传感器
定时中断基本结构
【10月更文挑战第21天】定时中断是在微控制器或计算机系统中,按预设时间间隔自动触发中断请求的机制。它由定时器硬件模块(含计数器、时钟源、控制寄存器)、中断控制器(处理中断请求、设置优先级、中断屏蔽)和中断服务程序(保存现场、执行任务、恢复现场)组成,实现定时任务的精确执行。
|
Linux 芯片
Linux中断处理机制
中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。
Linux中断处理机制
2.4总线操作和定时
2.4总线操作和定时
195 0
2.4总线操作和定时
|
缓存 编译器 Linux
CPU中断控制和并发处理的内核解析
CPU中断控制和并发处理的内核解析
CPU中断控制和并发处理的内核解析
|
缓存 Linux 开发工具