博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 定时器 网上转载的 作为参考
阅读量:4124 次
发布时间:2019-05-25

本文共 4060 字,大约阅读时间需要 13 分钟。

转载来自:http://www.xuebuyuan.com/1756473.html

http://blog.csdn.net/csdn_logo/article/details/48525703

在linux下提供了两种基本的Timer机制:alarm和settimer。

   1、alarm
    #include <unistd.h>
    unsigned int alarm(unsigned int seconds);
    这是个最简单的Timer,当调用了alarm(n)时,等待n秒后,就会触发一次SIGALRM信号,故需要在调用alarm函数前先设置好 SIGALRM信号对应的处理函数才行,而当调用alarm(0)时,表示停止当前的timer处理,不要发出SIGALRM信号。
    返回值:返回上一次调用alarm函数的剩余秒好,若之前没有调用alarm函数,则返回0。
    例(第一次等待1秒触发Timer,之后都是2秒触发):
     #include <iostream>
    #include <unistd.h>
    #include <signal.h>
 
    using namespace std;
 
    void my_alarm_handler(int a){
       cerr<<"my_alarm_handler"<<endl;
       alarm(2);//更改为2秒调用一次Timer
    }
 
    int main(){
       signal( SIGALRM, my_alarm_handler );
       alarm(1);
 
       while(1){}
 
       return 0;
     }
   2、settimer
     #include <sys/time.h>
    #define ITIMER_REAL 0
    #define ITIMER_VIRTUAL 1
    #define ITIMER_PROF 2
 
    int getitimer(int which, struct itimerval *value);
    int setitimer(int which, const struct itimerval *value,struct itimerval *ovalue);
    settimer和gettimer函数都提供了三种类别的Timer供使用:
    1)、ITIMER_REAL:以系统实际的时间来计算,触发时会发出SIGALRM信号。
    2)、ITIMER_VIRTUAL:只计算进程的执行时间(在用户态),触发时会发出SIGVTALRM信号。
    3)、ITIMER_PROF:计算进程在用户态和内核态的处理时间,触发时会发出SIGPROF信号。
    通过第一个参数which来指定要使用哪一种Timer(ITIMER_REAL、ITIMER_VIRTUAL、ITIMER_PROF)。 settimer函数是用来设置对应的Timer的触发时间是多少,而gettimer函数是用来获取上一次Timer设置的时间。设置的时间是一个结构 体struct itimerval:
     struct itimerval {
      struct timeval it_interval; 
      struct timeval it_value; 
    };
    struct timeval {
      long tv_sec; 
      long tv_usec; 
    };
    settimer由第二个参数value设置触发时间,第三个参数ovalue用来获取上一次settimer设置的itimerval值(该参数可以设 置为NULL)。对于itimerval里面变量的值,当我们设置it_interval的值为0时,Timer只会触发一次,而it_value设置为 0时则表示Timer结束。
    返回值:0为成功,-1为失败。
    例(第一次等待1秒触发Timer,之后都是2秒触发):
     #include <iostream>
    #include <sys/time.h>
    #include <signal.h>
 
    using namespace std;
 
    void my_alarm_handler(int a){
      cerr<<"test "<<endl;
    }
 
    int main(){
      struct itimerval t;
      t.it_interval.tv_usec = 0;
      t.it_interval.tv_sec = 2;
      t.it_value.tv_usec = 0;
      t.it_value.tv_sec = 1;
 
      if( setitimer( ITIMER_REAL, &t, NULL) < 0 ){
        cerr<<"settimer error."<<endl;
        return -1;
      }
      signal( SIGALRM, my_alarm_handler );
 
      while(1){
        sleep(2);
      }
      return 0;
    }
    通过上面的例子,我们可以知道对于linux内建Timer只能同一时间处理3个Timer,如果需要多个的话,那么这就是个问题了。不过我们可以通过sleep函数或time函数来结合使用实现定时功能

采样的时候要用到定时器,定时的进行采样。这时候,就会用到setitimer函数了。

1. 要使用setitimer函数,要包含头文件:#include <sys/time.h>

2. 该函数的原型是:int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

3. 参数:

(1)int which:定时器分以下三种

ITIMER_REAL:decrements in real time, and deliversSIGALRM upon expiration.

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

ITIMER_VIRTUAL:decrements only  when  the  process  is  executing,  anddeliversSIGVTALRM upon expiration.

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

ITIMER_PROF:decrements  both  when the process executes and when the system is executing on behalf 

of the  process. Coupledwith  ITIMER_VIRTUAL, this timer is usually used to profile the time

 spent by the application in user and  kernel space.  SIGPROF is delivered

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

(2)struct itimerval *new_value,其定义如下:

struct itimerval {  

               struct timeval it_interval; /* 定时器间隔时间 */  
               struct timeval it_value; /* 定时器开始运行延时时间 */  
           };  
struct timeval {  
               long tv_sec; /* 秒 */  
               long tv_usec; /* 微秒 */  
           };  

其中it_value表示设置定时器后间隔多久开始执行定时任务,而it_interval表示两次定时任务之间的时间间隔。

(3)上一次定时器的值,一般置为NULL即可

4. 返回值:成功返回0;失败返回-1,并把错误号写到errno变量中

5. 犯错笔记

5.1

[cpp]   
 
  1. ...  
  2. struct itimerval itv;  
  3.   
  4. if (signal(SIGALRM, samplingForComtrade) == SIG_ERR) {  
  5.     DBG("signal samplingForComtrade() bind failed !\n");  
  6.     exit(EXIT_FAILURE);  
  7. }  
  8. itv.it_value.tv_sec = 0;  
  9. itv.it_value.tv_usec = 0;  
  10. itv.it_interval.tv_sec = 0;  
  11. itv.it_interval.tv_usec = 1000;  
  12. if(setitimer(ITIMER_REAL,&itv,NULL) != 0){  
  13.     fprintf(stderr,"setitimer failed,errno = %d\n",errno);  
  14.     exit(EXIT_FAILURE);  
  15. }  
  16. ...  
  如上设置好后
samplingForComtrade()函数怎么也不跑起来,查问题查到绝望,最后才发现当你把it_value参数里面的秒和微秒全部设置为0时,定时器是跑不起来的。。。 

settimer工作机制是,先对it_value倒计时,当it_value为零时触发信号,然后重置为it_interval,继续对it_value倒计时,一直这样循环下去。

假如it_value为0是不会触发信号的,所以要能触发信号,it_value得大于0;如果it_interval为零,只会延时,不会定时(也就是说只会触发一次信号)。

5.2

setitimer()函数调用完,定时器就跑一次处理函数,第二次的时候打印出 Alarm clock ,然后程序直接退出。

查到想死才查出原因:原来是由于编译的时候加了编译条件 -std=c99, 会跟定时器冲突,去掉就行了。。。无语!

5.3

使用了定时器后sleep()函数就不好使了,因为sleep函数也是使用的SIGALRM信号。

解决办法是采用其他延时方式,如select等。

你可能感兴趣的文章
linux关闭防火墙了,但端口还是访问不了/虚拟机能ping通,但是telnet某个端口却不行
查看>>
StringBuffer的扩容机制为什么是两倍的原数组长度 + 2
查看>>
Java的double和float类型计算丢失精度问题,bigdecimal用法
查看>>
./configure make && make install 是什么意思
查看>>
springioc的好处
查看>>
git 远程仓库和本地仓库建立连接
查看>>
Mybatis Plus 如何通过lambda获取属性名的
查看>>
关于项目中空指针问题的处理
查看>>
MybatisPlus小记
查看>>
初识xsd
查看>>
java 设计模式-职责型模式
查看>>
构造型模式
查看>>
svn out of date 无法更新到最新版本
查看>>
java杂记
查看>>
RunTime.getRuntime().exec()
查看>>
Oracle 分组排序函数
查看>>
删除weblogic 域
查看>>
VMware Workstation 14中文破解版下载(附密钥)(笔记)
查看>>
日志框架学习
查看>>
日志框架学习2
查看>>