内核的定时机制

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

下面是程序的运行截图:

时间: 2024-10-16 07:38:51

内核的定时机制的相关文章

Linux 内核的定时机制实验

参考链接: Linux struct itimerval用法: http://blog.csdn.net/hbuxiaofei/article/details/35569229 Linux定时器实验: https://wenku.baidu.com/view/bb8416d2b9f3f90f76c61b8e.html

大话Linux内核中锁机制之RCU、大内核锁

大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linux内核中锁机制>系列博文进行了总结,并提出关于目前Linux内核中提供的锁机制的一些基本使用观点. 十.RCU机制 本节将讨论另一种重要锁机制:RCU锁机制.首先我们从概念上理解下什么叫RCU,其中读(Read):读者不需要获得任何锁就可访问RCU保护的临界

JavaScript可否多线程? 深入理解JavaScript定时机制

http://www.phpv.net/html/1700.html JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( function(){ alert(’你好!’); } , 0); setInterval( callbackFunction , 100); 认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是Java

JavaScript定时机制setTimeout与setInterval研究

JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout(function() { alert('你好!'); }, 0); setInterval(callbackFunction, 100); 认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被

linux笔记 2-3 系统延迟以及定时机制

**************3.系统延迟及定时机制************** ## 1.at延迟 ##at timeat> 动作at> ctrl+dat> <EOT>at -l                          查看等待任务atrm 任务号                    删除任务 例:设置延迟任务,在2:03时在/mnt新建文件test 当执行动作有输出时输出结果会以邮件形式发送给任务发起人mail                          

Linux 内核的同步机制,第 1 部分 + 第二部分(转)

http://blog.csdn.net/jk198310/article/details/9264721  原文地址: Linux 内核的同步机制,第 1 部分 一. 引言 在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上的执行单元对共享的数据的访问.在主流的Linux内核中包含了几乎所有现代的操作系统具有的同步机制,这些同步机制包括:原子操作

linux内核的配置机制及其编译过程

linux内核的配置机制及其编译过程 国嵌第一天第三节:讲解的是内核在X86平台上的配置.安装过程,制作自己的Linux系统,并双系统启动. <Linux系统移植>第四章 http://blog.csdn.net/zhengmeifu/article/details/7682373 Linux内核具有可定制的特点,具体步骤如下: 1.1.1 配置系统的基本结构 Linux内核的配置系统由三个部分组成,分别是: 1.Makefile:分布在 Linux 内核源代码根目录及各层目录中,定义 Lin

Linux内核抢占实现机制分析【转】

Linux内核抢占实现机制分析 转自:http://blog.chinaunix.net/uid-24227137-id-3050754.html [摘要]本文详解了Linux内核抢占实现机制.首先介绍了内核抢占和用户抢占的概念和区别,接着分析了不可抢占内核的特点及实时系统中实现内核抢占的必要性.然后分析了禁止内核抢占的情况和内核抢占的时机,最后介绍了实现抢占内核所做的改动以及何时需要重新调度. [关键字]内核抢占,用户抢占,中断, 实时性,自旋锁,抢占时机,调度时机,schedule,pree

用户权限及系统延时及定时机制

#####用户权限列表#############1.权限列表的定义######制定特殊用户对某个文件有特殊权限的记录表格######2.权限列表的识别######权限位有+ 权限列表中开启权限位是.,表示权限尚未开启######3.权限列表的查看######getfacl file##file:file          ##文件名称##owner:root         ##文件所有人##group:root         ##文件所有组#user::rw-            ##文件