zoukankan      html  css  js  c++  java
  • linux定时器【转】

    转自:http://www.cnblogs.com/processakai/archive/2012/04/11/2442294.html

    今天看书看到了关于alarm的一些用法,自己有在网上找了些资料看了下;
    1。alarm()执行后,进程将继续执行,在后期(alarm以后)的执行过程中将会在seconds秒后收到信号SIGALRM并执行其处理函数。

    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    void sigalrm_fn(int sig)
    {
        printf("alarm! ");
        alarm(2);
        return;
    }
    int main(void)
    {
        signal(SIGALRM, sigalrm_fn);
        alarm(1);
        while(1) pause();
    }


    2.alarm定时器,但是只能精确到秒,然而我们如果需要用到更精准的怎么办?
    经过群里的大牛知道,看了下可以用setitimer
     int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
     setitimer()比alarm功能强大,支持3种类型的定时器:
        ITIMER_REAL :     以系统真实的时间来计算,它送出SIGALRM信号。
        ITIMER_VIRTUAL : -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
        ITIMER_PROF :     以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
        setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例;第三个参数可不做处理。
        setitimer()调用成功返回0,否则返回-1。

        下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:[code=C/C++]
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <time.h>
    #include <sys/time.h>
    int sec;
    void sigroutine(int signo){
        switch (signo){
            case SIGALRM:
                printf("Catch a signal -- SIGALRM ");
                signal(SIGALRM, sigroutine);
                break;
            case SIGVTALRM:
                printf("Catch a signal -- SIGVTALRM ");
                signal(SIGVTALRM, sigroutine);
                break;
        }
        return;
    }
    int main()
    {
        struct itimerval value, ovalue, value2;          //(1)
        sec = 5;
        printf("process id is %d ", getpid());
        signal(SIGALRM, sigroutine);
        signal(SIGVTALRM, sigroutine);
        value.it_value.tv_sec = 1;
        value.it_value.tv_usec = 0;
        value.it_interval.tv_sec = 1;
        value.it_interval.tv_usec = 0;
        setitimer(ITIMER_REAL, &value, &ovalue);     //(2)
        value2.it_value.tv_sec = 0;
        value2.it_value.tv_usec = 500000;
        value2.it_interval.tv_sec = 0;
        value2.it_interval.tv_usec = 500000;
        setitimer(ITIMER_VIRTUAL, &value2, &ovalue);
        for(;;)
            ;
    }
    setitimer不会引起线程的阻塞、也不会引起线程的切换动作,就是简单的启动一个定时器,开始定时,而且这种定时应该是基于内核的,(windwos的settimer是基于一种消息的模型);setitimer虽然有三种类型ITIMER_REAL,ITIMER_VIRTUAL ITIMER_PROF,但是在同一时间同一进程,一种类型的只能有1个setitimer;
    如果我们需要多个定时器怎么办?
    3.

    [code=C/C++]
    #include<stdio.h>  
    #include<stdlib.h>  
    #include<time.h>  
    #include<sys/time.h>  
    #include<errno.h>  
    #include<string.h>  
    #include<unistd.h>  
    #include<sys/types.h>  
    #include<sys/select.h>  
     
     
    int main(int argc, char **argv) 

        unsigned int nTimeTestSec = 0; 
        unsigned int nTimeTest = 0; 
        struct timeval tvBegin; 
        struct timeval tvNow; 
        int ret = 0; 
        unsigned int nDelay = 0; 
        struct timeval tv; 
        int fd = 1; 
        int i = 0; 
        struct timespec req; 
     
        unsigned int delay[20] =  
            {500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0}; 
        int nReduce = 0; //误差  
     
        fprintf(stderr, "%19s%12s%12s%12s ", "fuction", "time(usec)", "realtime", "reduce"); 
        fprintf(stderr, "---------------------------------------------------- "); 
        for (i = 0; i < 20; i++) 
        { 
            if (delay[i] <= 0) 
                break; 
            nDelay = delay[i]; 
            //test sleep  
            gettimeofday(&tvBegin, NULL); 
            ret = usleep(nDelay); 
            if(ret == -1) 
            { 
                fprintf(stderr, "usleep error, errno=%d [%s] ", errno, strerror(errno)); 
            } 
            gettimeofday(&tvNow, NULL); 
            nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec; 
            nReduce = nTimeTest - nDelay; 
     
             fprintf (stderr, " usleep       %8u   %8u   %8d ", nDelay, nTimeTest,nReduce); 
     
             //test nanosleep  
             req.tv_sec = nDelay/1000000; 
             req.tv_nsec = (nDelay%1000000) * 1000; 
     
             gettimeofday(&tvBegin, NULL); 
             ret = nanosleep(&req, NULL); 
             if (-1 == ret) 
             { 
                fprintf (stderr, " nanousleep   %8u   not support ", nDelay); 
             } 
             gettimeofday(&tvNow, NULL); 
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec; 
             nReduce = nTimeTest - nDelay; 
             fprintf (stderr, " nanosleep    %8u   %8u   %8d ", nDelay, nTimeTest,nReduce); 
     
             //test select  
             tv.tv_sec = 0; 
             tv.tv_usec = nDelay; 
     
             gettimeofday(&tvBegin, NULL); 
             ret = select(0, NULL, NULL, NULL, &tv); 
             if (-1 == ret) 
             { 
                fprintf(stderr, "select error. errno = %d [%s] ", errno, strerror(errno)); 
             } 
     
             gettimeofday(&tvNow, NULL); 
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec; 
             nReduce = nTimeTest - nDelay; 
             fprintf (stderr, " select       %8u   %8u   %8d ", nDelay, nTimeTest,nReduce); 
     
             //pselcet  
             req.tv_sec = nDelay/1000000; 
             req.tv_nsec = (nDelay%1000000) * 1000; 
     
             gettimeofday(&tvBegin, NULL); 
             ret = pselect(0, NULL, NULL, NULL, &req, NULL); 
             if (-1 == ret) 
             { 
                fprintf(stderr, "select error. errno = %d [%s] ", errno, strerror(errno)); 
             } 
     
             gettimeofday(&tvNow, NULL); 
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec; 
             nReduce = nTimeTest - nDelay; 
             fprintf (stderr, " pselect      %8u   %8u   %8d ", nDelay, nTimeTest,nReduce); 
     
             fprintf (stderr, "-------------------------------- "); 
     
        } 
         
        return 0; 

    [/code]

    int msSleep(long ms) {

        struct timeval tv;

        tv.tv_sec = 0;

        tv.tv_usec = ms;

         return select(0, NULL, NULL, NULL, &tv);

    }


    上面这段代码作者有这样的话
    “老大建议我们在对精度要求较高的情况下使用select()作为定时器,最大的好处就是不会影响信号处理线程安全,而且精度能得到保证。在这个实验中,当时间延时时间较长时,select和pselect表现较差,当时间小于1毫秒时,他们的精确度便提高了,表现与usleep、nanosleep不相上下,有时精度甚至超过后者。

    查了下上面4个函数,select,和sleep是可重入函数,在使用的时候会引起线程的切换;所以有“不会影响信号处理线程安全”而usleep,nanosleep,不可重入函数,程序是在暂停状态,也就是不能线程切换;但是不知道setitimer会不会记时;

  • 相关阅读:
    下载安装Cygwin
    WEB中调用Nutch执行JOB抓取
    IKAnalyzer 分词
    【转】JDBC连接数据库
    单例模式的常见写法
    14 Go's Declaration Syntax go语言声明语法
    13 JSON-RPC: a tale of interfaces
    12 Release History for go go语言的版本历史
    11 The Go Memory Model go语言内置模型
    09 Command Documentation 命令文档
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/9304486.html
Copyright © 2011-2022 走看看