linux 内核微秒定时函数_linux c++ 统计函数运行时间 微秒级 - CSDN
  •  在linux下如果定时如果要求不太精确的话,使用alarm()和signal()就行了(精确到秒),但是如果想要实现精度较高的定时功能的话,就要使用setitimer函数。  setitimer()为Linux的API,并非C语言的Standard ...

    1.介绍

      在linux下如果定时如果要求不太精确的话,使用alarm()和signal()就行了(精确到秒),但是如果想要实现精度较高的定时功能的话,就要使用setitimer函数。

      setitimer()为Linux的API,并非C语言的Standard Library,setitimer()有两个功能,一是指定一段时间后,才执行某个function,二是每间格一段时间就执行某个function, 以下程序demo如何使用setitimer()。

    2.函数参数

    int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
    
      struct itimerval {
      struct timeval it_interval;
      struct timeval it_value;
      };
      struct timeval {
      long tv_sec;
      long tv_usec;
      };


    其中,which为定时器类型,3中类型定时器如下:

      ITIMER_REAL : 以系统真实的时间来计算,它送出SIGALRM信号。  

      ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。  

      ITIMER_PROF : 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。

      第二个参数指定间隔时间,第三个参数用来返回上一次定时器的间隔时间,如果不关心该值可设为NULL。

      it_interval指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。  

      tv_sec提供秒级精度,tv_usec提供微秒级精度,注意1s = 1000000us,并且两者共同表示定时的间隔,如tv_sec=1,tv_usec=500000,则表示定时1.5s。 

      如果是以setitimer提供的定时器来休眠,只需阻塞等待定时器信号就可以了。

      setitimer()调用成功返回0,否则返回-1。

    该示例程序每隔1.5s产生一行标准输出。

    #include <stdio.h>        //printf()
    #include <unistd.h>        //pause()
    #include <signal.h>        //signal()
    #include <string.h>        //memset()
    #include <sys/time.h>    //struct itimerval, setitimer()
    
    static int count = 0;
    
    void printMes(int signo)
    {
        printf("Get a SIGALRM, %d counts!\n", ++count);
    }
    
    int main()
    {
        int res = 0;
        struct itimerval tick;
        
        signal(SIGALRM, printMes);
        memset(&tick, 0, sizeof(tick));
    
        //Timeout to run first time
        tick.it_value.tv_sec = 1;
        tick.it_value.tv_usec = 500000;
    
        //After first, the Interval time for clock
        tick.it_interval.tv_sec = 1;
        tick.it_interval.tv_usec = 500000;
    
        if(setitimer(ITIMER_REAL, &tick, NULL) < 0)
                printf("Set timer failed!\n");
    
        //When get a SIGALRM, the main process will enter another loop for pause()
        while(1)
        {
            pause();
        }
        return 0;
    }



    展开全文
  • 此时我们首先想到了定时器,在普通的单片机中,芯片原厂提供了一些通用的API函数用于实现该类型的任务,同样的,在基于Linux内核的操作系统中,同样的而又这么一组函数,可以实现同样的操作。 首先是低精度的的...

    在Linux内核中我们时常需要完成一些周期性的任务,此时我们首先想到了定时器,在普通的单片机中,芯片原厂提供了一些通用的API函数用于实现该类型的任务,同样的,在基于Linux内核的操作系统中,同样的而又这么一组函数,可以实现同样的操作。

    首先是低精度的的定时器,在Linux2.6.4之前的版本上没有高精度定时器的情况下,低精度的定时器就成了首选,但是这种低精度的定时器他有个缺点,他的最高精度只能达到毫秒级别,大概是10ms左右。这种内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,我们可以在他的回调函数中实现一些自己的功能。

    查阅Linux内核源码可知,定时器的数据结构如下:

    struct timer_list {
    
            struct list_head entry;
    
            unsigned long expires;
    
            void (*function)(unsigned long);
    
            unsigned long data;
    
           struct tvec_base *base;
    
           ......
    
    };
    

    其中expires字段表示期望定时器执行的jiffies值,到达jiffies值时,将调用function函数,并传递data作为参数(如果function函数需要不止一个参数时,那么可以将几个参数组成一个结构体,并将结构体的指针赋值给data)。当一个定时器被注册到内核之后,entry字段用来连接该定时器到一个内核链表中。base字段是内核内部实现所使用的字段。

    定时器初始化时,我们可以采用如下的方法:

    struct timer_list mytimer;
    
    init_timer(&mytimer);    
    
    mytimer ->timer.expires = jiffies + 5*HZ;
    
    mytimer ->timer.data = (unsigned long) dev;
    
    mytimer ->timer.function = &corkscrew_timer; /* timer handler */
    

    初始化:

    使用init_timer( )函数可以定义一个定时器,在执行add_timer()之前给timer_list结构体赋值进行参数设置。

    注册:

    使用如下函数:

    add_timer(struct timer_list *timer);使用该函数,初始化的定时器会被连接到内核专门的链表中。

    定时运行过程中的定时器周期修改:

    mod_timer(struct timer_list *timer, unsigned long expires);该函数会重新注册定时器到内核,而不管定时器函数是否被运行过。

    注销定时器:

    del_timer(struct timer_list *timer);

    定时器状态判断:

    int timer_pending(const struct timer_list *timer); 这个函数用来判断一个定时器是否被添加了内核链表中以等待被调度。

    以下是使用定时器的一个例子:

    void slow_timer_init(int msecs, void *function, int para)
    {
        static struct timer_list timer;
        
        if(NULL == function)
        {
            del_timer(&timer);    // 删除定时器
            return ;
        }
        
        init_timer(&timer);        
        timer.data = para;
    //    timer.expires = jiffies + ((msecs * 1000) * HZ);        // 另外一种方式
        timer.expires = jiffies + msecs_to_jiffies(msecs);        // 毫秒
        timer.function = function;
        add_timer(&timer);    
        
        return ;
    }

     

    展开全文
  • linux信号应用,定时执行,alarm,setitimer
    

    前言:

    linux中信号提供了软中断的作用。提供了一种处理异步时间的方法 ,  可以通过信号合理的安排异步任务。

    linux定义了以下主要的系统信号:

    名称                        默认动作                        说明
     
    SIGHUP                   终止进程                        终端线路挂断
    SIGINT                   终止进程                        中断进程
    SIGQUIT                 建立CORE文件                 终止进程,并且生成core文件
    SIGILL                    建立CORE文件                非法指令
    SIGTRAP                 建立CORE文件                 跟踪自陷
    SIGBUS                  建立CORE文件                总线错误
    SIGSEGV                建立CORE文件                段非法错误
    SIGFPE                  建立CORE文件                浮点异常
    SIGIOT                  建立CORE文件                 执行I/O自陷
    SIGKILL                 终止进程                      杀死进程
    SIGPIPE                终止进程                      向一个没有读进程的管道写数据
    SIGALARM             终止进程                     计时器到时
    SIGTERM              终止进程                       软件终止信号
    SIGSTOP              停止进程                     非终端来的停止信号
    SIGTSTP              停止进程                      终端来的停止信号
    SIGCONT              忽略信号                    继续执行一个停止的进程
    SIGURG                忽略信号                       I/O紧急信号
    SIGIO                  忽略信号                       描述符上可以进行I/O
    SIGCHLD              忽略信号                    当子进程停止或退出时通知父进程
    SIGTTOU              停止进程                      后台进程写终端
    SIGTTIN               停止进程                         后台进程读终端
    SIGXGPU               终止进程                       CPU时限超时
    SIGXFSZ              终止进程                        文件长度过长
    SIGWINCH           忽略信号                     窗口大小发生变化
    SIGPROF             终止进程                       统计分布图用计时器到时
    SIGUSR1             终止进程                   用户定义信号1
    SIGUSR2             终止进程                   用户定义信号2
    SIGVTALRM        终止进程                     虚拟计时器到时

    应用:

    下面我们应用SIGALARM,设置每秒执行一次的动作:

    
        struct itimerval oneSec;
    
         signal(SIGALRM, Demo_updateTime);
            oneSec.it_value.tv_sec = 1;
            oneSec.it_value.tv_usec = 0;
            oneSec.it_interval.tv_sec = 1;
            oneSec.it_interval.tv_usec = 0;
            setitimer(ITIMER_REAL, &oneSec, NULL);
    

    Demo_updateTime()函数就是注册的每秒执行一次的函数。

     switch(signo){
            case SIGALRM:
                time(&timeval) ;
    
                localtime_r(&timeval, &tmCur) ;
    
                //update date only once one day
                if(tmOld.tm_mday != tmCur.tm_mday)
                {
                    char temp[40];
    
                    //get day of week from this call only.
                    ctime_r(&timeval, temp);
    
                    sprintf(osdStr,"%04d-%02d-%02d ",tmCur.tm_year+1900,
                            tmCur.tm_mon+1,tmCur.tm_mday);
    
                    strncat(osdStr,temp,3);
    
                }


    实现精度较高的定时功能的话,就要使用setitimer函数。

    int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
    which为定时器类型,setitimer支持3种类型的定时器:
    ITIMER_REAL: 以系统真实的时间来计算,它送出SIGALRM信号。
    ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
    ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
    setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
    setitimer()调用成功返回0,否则返回-1。
    struct itimerval {
    
    struct timeval it_interval;
    
    struct timeval it_value;
    
    };
    
    struct timeval {
    
    long tv_sec;
    
    long tv_usec;
    
    };
    需要signal.h和sys/time.h
    it_interval指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。
    tv_sec提供秒级精度,tv_usec提供微秒级精度,以值大的为先,注意1s = 1000000us。
    ovalue用来保存先前的值,常设为NULL。

          如果不需要这么高的精度,可用用alarm()函数:

    ALARM介绍

    alarm也称为闹钟函数alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。要注意的是,一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替

    所需头文件
      #include<unistd.h>


    函数原型
      unsigned int alarm(unsigned int seconds)


    函数参数
      seconds:指定秒数


    函数返回值
      成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
      出错:-1

    展开全文
  • 实验内容 A 在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)。 B 用定时器 ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,计算已经过的秒数。...

    1 实验目的
    本实验是练习怎样编写调用内核的时间测量功能为应用程序测量和精确定时。通过这个实验我们可以进一步理解 Linux 内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。
    2 实验内容
    A 在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)。
    B 用定时器 ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,计算已经过的秒数。
    C 记录一个进程运行时所占用的real time,cpu time, user time, kernel time
    3 实验说明
    1) 系统时间的获取和内核定时机制
    从用户空间去获取系统时间数据需要以下基本代码:

    #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_valueit_real_incr字段有关。
    ITIMER_VIRTUAL:反映进程经过的虚拟时间,只有相关进程正在执行时该时间才会增加。这种定时器到时后发 SIGVTALRM 信号。与struct task_struct 结构中的 it_virt_valueit_virt_incr字段有关
    ITIMER_PROF:反映进程经过的虚拟时间加上内核为相关进程执行工作的时间之和。这种定时 器 到 时 后 发SIGPROF 信 号 。 与struct task_struct 结 构 中 的 it_prof_value it_prof_incr `字段有关。
    每个定时器需要周期性的设定一个初始时间值,之后递减计数到 0 后引发定时中断,产生超时信号通知对应进程定时器时间到,然后定时器重新从设置的初始值再次开始递减计数。
    2) 定时器的使用
    定时器使用:定时器的使用只须执行一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。

    定时器的使用步骤
     初始化,
     设置一个超时时间,
     指定超时发生时执行的函数,
     激活定时器。

    3) 使用定时器时的函数
    (1) 初始化:三种定时器都使用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 //定时器当前值
    } ;

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

    #include <sys/time.h>
    …
    函数getitimer(int timerType ,//定时器类型
    const struct itimerval *value, //定时器当前的秒数和毫秒数
    )

    (3) 各类定时器到时的信号处理函数可以使用系统调用函数指定:

    sighandler_t signal(int signum, //信号类型
    sighandler_t handler //信号处理函数名
    );

    4 实验程序:
    A 在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)。
    设计思路:
    设置定时器 ITIMER_REAL间隔为一秒钟。并为计时到时设定信号处理程序,使其输出当前所记时间。定时3秒,计时结束,给出提示、终止程序。
    程序源代码清单:

    /****test3.c*****/
    #include <sys/time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    static void sighandle(int);
    static int second = 0;
    int main(){
    struct itimerval v;
    signal(SIGALRM,sighandle);
    v.it_interval.tv_sec = 1;
    v.it_interval.tv_usec = 0;
    v.it_value.tv_sec = 1;
    v.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL,&v,NULL);
    for(;;);
    }
    static void sighandle(int s)
    {
    second++;
    if(second<=3)
    printf("%d\r",second);
    else abort();
    fflush(stdout);
    }

    运行结果:
    这里写图片描述
    这里写图片描述
    B 用定时器ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,计算已经过的秒数。
    设计思路:
    设置定时器ITIMER_REAL间隔为一秒钟。并为计时到时设定信号处理程序,即 singal(SIGALRM,⋯),使其输出当前所记时间。
    程序源代码清单:

    /****test1.c*****/
    #include <sys/time.h>
    #include <stdio.h>
    #include <signal.h>
    static void sighandle(int);
    static int second = 0;
    int main(){
    struct itimerval v;
    signal(SIGALRM,sighandle);
    v.it_interval.tv_sec = 1;
    v.it_interval.tv_usec = 0;
    v.it_value.tv_sec = 1;
    v.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL,&v,NULL);
    for(;;);
    }
    static void sighandle(int s)
    {second++;
    printf("%d\r",second);
    fflush(stdout);
    }

    运行结果:每隔一秒结果+1
    这里写图片描述

    C 记录一个进程运行时所占用的real time, cpu time, user time, kernel time
    设计思路:
    任务开始前设置好定时器ITIMER_REALITIMER_VIRTUALITIMER_PROF,即 其相应的信号处理程序。在任务执行过程中内核定时器通过产生等间隔的信号来记录进程所需的各种时间参量,并在任务结束后打印出来。
    程序源代码清单 :

    /************test2.c**********/
    #include <sys/time.h>
    #include <stdio.h>
    #include <signal.h>
    static void sighandle(int);
    static long realsecond = 0;
    static long vtsecond = 0;
    static long profsecond = 0;
    static struct itimerval realt,virtt,proft;int main(){
    struct itimerval v;
    int i,j;
    long moresec,moremsec,t1,t2;
    signal(SIGALRM,sighandle);
    signal(SIGVTALRM,sighandle);
    signal(SIGPROF,sighandle);
    v.it_interval.tv_sec = 10;
    v.it_interval.tv_usec = 0;
    v.it_value.tv_sec = 10;
    v.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL,&v,NULL);
    setitimer(ITIMER_VIRTUAL,&v,NULL);
    setitimer(ITIMER_PROF,&v,NULL);
    for(j= 0;j<1000;j++){
    for(i= 0;i<500;i++){printf("********\r");fflush(stdout);}
    }
    getitimer(ITIMER_PROF,&proft);
    getitimer(ITIMER_REAL,&realt);
    getitimer(ITIMER_VIRTUAL,&virtt);
    printf("\n");
    moresec = 10 - realt.it_value.tv_sec;
    moremsec = (1000000 - realt.it_value.tv_usec)/1000;
    printf("realtime = %ld sec, %ld msec\n",realsecond+moresec,moremsec);
    moresec = 10 - proft.it_value.tv_sec;
    moremsec = (1000000 - proft.it_value.tv_usec)/1000;
    printf("cputime = %ld sec, %ld msec\n",profsecond+moresec,moremsec);
    moresec = 10 - virtt.it_value.tv_sec;
    moremsec = (1000000 - virtt.it_value.tv_usec)/1000;
    printf("usertime = %ld sec, %ld msec\n",vtsecond+moresec,moremsec);
    t1 = (10 - proft.it_value.tv_sec)*1000 + (1000000 - proft.it_value.tv_usec)/1000 +
    profsecond*10000;
    t2 = (10 - virtt.it_value.tv_sec)*1000 + (1000000 - virtt.it_value.tv_usec)/1000 +
    vtsecond*10000;
    moresec = (t1 - t2)/1000;
    moremsec = (t1 - t2) % 1000;
    printf("kerneltime = %ld sec, %ld msec\n",moresec,moremsec);
    fflush(stdout);}
    static void sighandle(int s)
    {
    switch(s){
    case SIGALRM:realsecond+=10;break;
    case SIGVTALRM:vtsecond+=10;break;
    case SIGPROF:profsecond+=10;break;
    default :break;
    }
    }

    运行结果:
    这里写图片描述

    展开全文
  • 5-3 Linux内核计时、延时函数与内核定时器 计时 1、内核时钟 1.1内核通过定时器(timer)中断来跟踪时间流 1.2硬件定时器以周期性的间隔产生时间中断,这个间隔(即频率)由内核根据HZ来确定,HZ是一个与体系...
  • linux内核时间子系统
  • Linux内核的基本概念

    2019-04-20 14:20:09
    Linux内核的基本概念——将所有化为最简单物理地址VS虚拟地址Linux内核中的内存管理系统调用内核线程内核中的同步和线程间通信的方式中断时钟和定时器管理文件系统 物理地址VS虚拟地址 Linux所使用的地址是虚拟...
  • Linux 内核时间管理

    2019-01-29 11:03:47
    相对于事件驱动,内核中有大量的函数都是基于时间驱动的。内核必须管理系统的运行时间以及当前的日期和时间。  周期产生的事件都是由系统定时器驱动的。系统定时器是一种可编程硬件芯片,它已固定频率产生中断。该...
  • QT精确延时定时函数

    2019-01-09 11:12:22
    sleep函数并不能起到定时的作用,主要作用是延时。在一些多线程中可能会看到sleep(0);其主要目的是让出时间片。 sleep函数的精度非常低,当系统越繁忙的时候它精度也就越低,有时候我们休眠1秒,可能3秒后才能继续...
  • 内核定时机制应用

    2019-09-10 00:03:58
    通过该练习我们可以进一步理解 Linux 内核定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。 从用户空间去获取系统时间数据需要以下基本代码: #include <sys/time> st...
  • 定时器是一种软件功能,即允许在将来的某个时刻,函数在给定的时间间隔用完时被调用。超时表示与定时器相关的时间间隔已经用完的那个时刻。 linux上考虑两种类型的定时器,即动态定时和间隔定时器。第一种类型由...
  • Linux内核高精度定时器hrtimer的使用 hrtimer:(high resolution timer): 高精度定时器,为我们提供了纳秒级别的定时精度,以满足对精确时间有迫切需求的应用程序或内核驱动。因原有定时器已经相对完善,避免大...
  • Linux内核中有大量的函数需要时间管理,比如延时程序、周期性的程序调度等。硬件定时器提供时钟源,时钟源的频率是可以设置的,设置好以后通过周期性中断来计时。 周期性中断的频率也叫系统节拍,系统节拍在编译内核...
  • Linux内核中,高度依赖于时间信息(不管这个时间是精确的或非精确的),比如硬件驱动中的延时、延后访问等等。在内核中通过定时器来精确的度量时间,那么这个定时的时间间隔取决于HZ这个值,它是与体系结构相关的...
  • 中断潜伏期是由于内核在进入临界区前关闭CPU的中断响应所引起的,在这个时间段内,虽然外部设备使CPU的中断请求线有效,但CPU并不立刻响应中断,而是继续执行临界区的内核代码,直至退出临界区、使能中断请求,才...
  • 内核同步 内核抢占 原子操作 位锁 内存屏障 自旋锁 位图操作 顺序锁 信号量 PerCPU 读写信号量 完成变量 中断操作 工作队列 等待队列 内存管理 物理页管理 非整页内存管理 非连续内存管理 ...
  • Linux内核时钟中断设施linux的时钟中断需要两个全局变量,分别是xtime与jiffies。1、xtime一个timeval结构类型变量,是从cmos电路中取得的时间,一般是从某一历史时刻开始到现在的时间,也就是为了取得我们操作系统...
  • 【摘要】本文分析了Linux内核对于信号的实现机制和应用层的相关处理。首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理。接着分析了内核对于信号的处理流程包括信号的触发/注册/执行及...
1 2 3 4 5 ... 20
收藏数 1,603
精华内容 641
关键字:

linux 内核微秒定时函数