文档章节

内核的定时机制应用

陈洪波
 陈洪波
发布于 2015/05/19 19:32
字数 2272
阅读 5
收藏 0

练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。通过该练习我们可以进一步理解 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);
}

下面是程序的运行截图:

本文转载自:http://blog.csdn.net/hongbochen1223/article/details/45604779

陈洪波
粉丝 2
博文 76
码字总数 1552
作品 0
济南
程序员
私信 提问
Android基础之Android系统架构

Android采用层次化系统架构,官方公布的标准架构如下图所示。Android由底层往上分为4个主要功能层,分别是linux内核层(Linux Kernel),系统运行时库层(Libraries和Android Runtime),应用...

柳哥
2014/11/28
10.7K
2
全球最低功耗蓝牙单芯片DA14580的软件体系 -RW内核和消息处理机制

上一篇文章《蓝牙单芯片DA14580的硬件架构和低功耗》阐述了DA14580的硬件架构和低功耗的工作原理。本文文章阐述该平台的软件体系,并着重分析消息事件的处理机制。 一、DA14580SOC硬件组成和...

yueqian_scut
2016/04/10
0
0
LwIP源代码文件目录解析

原文地址:http://blog.csdn.net/liverpoolsun/article/details/19674319 1 -- LwIP源代码文件目录 root@motadou:/home/motadou/lwip/lwip-1.4.1# tree .├── CHANGELOG├── COPYING├─......

Iammalt
2017/09/13
0
0
JavaScript定时机制setTimeout与setInterval研究

容易欺骗别人感情的JavaScript定时器 本文转自:爱微网 JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都...

西西爱OS
2012/10/25
76
0
linux新内核的时钟机制代码读后感

如果说cfs是linux的一个很有创意的机制的话,那么linux中另一个创意就是nohz,我在前面已 经写了好几篇关于nohz的文章了,因此本文就不再阐述代码细节了,linux的创意在于设计而不在代码,代...

晨曦之光
2012/04/10
422
0

没有更多内容

加载失败,请刷新页面

加载更多

聊聊Tomcat中的连接器(Connector)

上期回顾 上一篇文章《Tomcat在SpringBoot中是如何启动的》从main方法启动说起,窥探了SpringBoot是如何启动Tomcat的,在分析Tomcat中我们重点提到了,Tomcat主要包括2个组件,连接器(Conne...

木木匠
40分钟前
3
0
OSChina 周一乱弹 —— 熟悉的味道,难道这就是恋爱的感觉

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @xiaoshiyue :好久没分享歌了分享张碧晨的单曲《今后我与自己流浪》 《今后我与自己流浪》- 张碧晨 手机党少年们想听歌,请使劲儿戳(这里)...

小小编辑
今天
1K
20
SpringBoot中 集成 redisTemplate 对 Redis 的操作(二)

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二) List 类型的操作 1、 向列表左侧添加数据 Long leftPush = redisTemplate.opsForList().leftPush("name", name); 2、 向列表右......

TcWong
今天
28
0
排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
昨天
4
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
昨天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部