使用定时器的目的无非是为了周期性的执行某一任务,或者是到了一个指定时间去执行某一个任务。要达到这一目的,一般有两个常见的比较有效的方法。一个是用linux内部的三个定时器,另一个是用sleep, usleep函数让进程睡眠一段时间,使用alarm定时发出一个信号,还有那就是用gettimeofday, difftime等自己来计算时间间隔,然后时间到了就执行某一任务,但是这种方法效率低,所以不常用。

alarm

alarm用在不需要经确定时的时候,返回之前剩余的秒数。

NAME
       alarm - set an alarm clock for delivery of a signal
SYNOPSIS
       #include <unistd.h>
       unsigned int alarm(unsigned int seconds);
DESCRIPTION
       alarm  arranges  for a SIGALRM signal to be delivered to the process in
       seconds seconds.
       If seconds is zero, no new alarm is scheduled.
       In any event any previously set alarm is cancelled.

测试程序:

 cat timer.c
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
 
void func()
{
        printf("2 s reached.\n");
10  }
11   
12  int main()
13  {
14          signal(SIGALRM,func);
15          alarm(2);
16          while(1);
17          return 0;
18  }
19   

Linux内置的3个定时器

Linux为每个任务安排了3个内部定时器:

ITIMER_REAL:实时定时器,不管进程在何种模式下运行(甚至在进程被挂起时),它总在计数。定时到达,向进程发送SIGALRM信号。

ITIMER_VIRTUAL:这个不是实时定时器,当进程在用户模式(即程序执行时)计算进程执行的时间。定时到达后向该进程发送SIGVTALRM信号。

ITIMER_PROF:进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计数。定时到达产生SIGPROF信号。ITIMER_PROF记录的时间比ITIMER_VIRTUAL多了进程调度所花的时间。

定时器在初始化是,被赋予一个初始值,随时间递减,递减至0后发出信号,同时恢复初始值。在任务中,我们可以一种或者全部三种定时器,但同一时刻同一类型的定时器只能使用一个。

用到的函数有:

#include <sys/time.h>
int getitimer(int which, struct itimerval *value);
int setitimer(int which, struct itimerval*newvalue, struct itimerval* oldvalue);
strcut timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
struct itimerval
{
struct timeval it_interval; /*时间间隔*/
struct timeval it_value;   /*当前时间计数*/
};

it_interval用来指定每隔多长时间执行任务, it_value用来保存当前时间离执行任务还有多长时间。比如说, 你指定it_interval为2秒(微秒为0),开始的时候我们把it_value的时间也设定为2秒(微秒为0),当过了一秒, it_value就减少一个为1, 再过1秒,则it_value又减少1,变为0,这个时候发出信号(告诉用户时间到了,可以执行任务了),并且系统自动把it_value的时间重置为it_interval的值,即2秒,再重新计数。

为了帮助你理解这个问题,我们来看一个例子:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
 
/*
*******************************************************************************************************
** Function name: main()
** Descriptions : Demo for timer.
** Input        : NONE
10  ** Output       : NONE
11  ** Created by   : Chenxibing
12  ** Created Date : 2005-12-29
13  **-----------------------------------------------------------------------------------------------------
14  ** Modified by  :
15  ** Modified Date:
16  **-----------------------------------------------------------------------------------------------------
17  *******************************************************************************************************
18  */
19  int limit = 10;
20  /* signal process */
21  void timeout_info(int signo)
22  {
23      if(limit == 0)
24      {
25          printf("Sorry, time limit reached.\n");
26          return;
27      }
28      printf("only %d senconds left.\n", limit--);
29  }
30   
31  /* init sigaction */
32  void init_sigaction(void)
33  {
34      struct sigaction act;
35   
36      act.sa_handler = timeout_info;
37      act.sa_flags   = 0;
38      sigemptyset(&act.sa_mask);
39      sigaction(SIGPROF, &act, NULL);
40  }
41   
42  /* init */
43  void init_time(void)
44  {
45      struct itimerval val;
46   
47      val.it_value.tv_sec = 1;
48      val.it_value.tv_usec = 0;
49      val.it_interval = val.it_value;
50      setitimer(ITIMER_PROF, &val, NULL);
51  }
52   
53   
54  int main(void)
55  {
56      init_sigaction();
57      init_time();
58      printf("You have only 10 seconds for thinking.\n");
59   
60      while(1);
61     return 0;
62  }
63   

对于ITIMER_VIRTUAL和ITIMER_PROF的使用方法类似,当你在setitimer里面设置的定时器为ITIMER_VIRTUAL的时候,你把sigaction里面的SIGALRM改为SIGVTALARM, 同理,ITIMER_PROF对应SIGPROF。

不过,你可能会注意到,当你用ITIMER_VIRTUAL和ITIMER_PROF的时候,你拿一个秒表,你会发现程序输出字符串的时间间隔会不止2秒,甚至5-6秒才会输出一个,至于为什么,自己好好琢磨一下^_^

sleep

下面我们来看看用sleep以及usleep怎么实现定时执行任务。

  1. #include <signal.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. static char msg[] = "I received a msg.\n";
  6. int len;
  7. void show_msg(int signo)
  8. {
  9. write(STDERR_FILENO, msg, len);
  10. }
  11. int main()
  12. {
  13. struct sigaction act;
  14. union sigval tsval;
  15. act.sa_handler = show_msg;
  16. act.sa_flags = 0;
  17. sigemptyset(&act.sa_mask);
  18. sigaction(50, &act, NULL);
  19. len = strlen(msg);
  20. while ( 1 )
  21. {
  22. sleep(2); /*睡眠2秒*/
  23. /*向主进程发送信号,实际上是自己给自己发信号*/
  24. sigqueue(getpid(), 50, tsval);
  25. }
  26. return 0;
  27. }

看到了吧,这个要比上面的简单多了,而且你用秒表测一下,时间很准,指定2秒到了就给你输出一个字符串。所以,如果你只做一般的定时,到了时间去执行一个任务,这种方法是最简单的。

时间差

下面我们来看看,通过自己计算时间差的方法来定时:

  1. #include <signal.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <time.h>
  6. static char msg[] = "I received a msg.\n";
  7. int len;
  8. static time_t lasttime;
  9. void show_msg(int signo)
  10. {
  11. write(STDERR_FILENO, msg, len);
  12. }
  13. int main()
  14. {
  15. struct sigaction act;
  16. union sigval tsval;
  17. act.sa_handler = show_msg;
  18. act.sa_flags = 0;
  19. sigemptyset(&act.sa_mask);
  20. sigaction(50, &act, NULL);
  21. len = strlen(msg);
  22. time(&lasttime);
  23. while ( 1 )
  24. {
  25. time_t nowtime;
  26. /*获取当前时间*/
  27. time(&nowtime);
  28. /*和上一次的时间做比较,如果大于等于2秒,则立刻发送信号*/
  29. if (nowtime - lasttime >= 2)
  30. {
  31. /*向主进程发送信号,实际上是自己给自己发信号*/
  32. sigqueue(getpid(), 50, tsval);
  33. lasttime = nowtime;
  34. }
  35. }
  36. return 0;
  37. }

这个和上面不同之处在于,是自己手工计算时间差的,如果你想更精确的计算时间差,你可以把 time 函数换成gettimeofday,这个可以精确到微妙。

上面介绍的几种定时方法各有千秋,在计时效率上、方法上和时间的精确度上也各有不同,采用哪种方法,就看你程序的需要。

https://blog.csdn.net/skc361/article/details/20544933

Linux定时器的使用(三种方法)的更多相关文章

  1. Linux 下系统调用的三种方法

    系统调用(System Call)是操作系统为在用户态运行的进程与硬件设备(如CPU.磁盘.打印机等)进行交互提供的一组接口.当用户进程需要发生系统调用时,CPU 通过软中断切换到内核态开始执行内核系 ...

  2. linux虚拟主机的三种方法

    虚拟主机虚拟主机是将一台(或者一组)服务器的资源(系统资源.网络带宽.存储空间等)按照一定的比例分割成若干相对独立的“小主机”的技术.每一台这样的“小主机”在功能上都可以实现WWW.FTP.Mail等 ...

  3. 【转】 Linux 线程同步的三种方法

    线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...

  4. 用Python获取Linux资源信息的三种方法

    方法一:psutil模块 #!usr/bin/env python # -*- coding: utf-8 -*- import socket import psutil class NodeReso ...

  5. 5.linux 软件安装的三种方法

      一.linux 操作系统中 软件的分类 以及软件的安装     vmtools  调用了perl语言写的安装脚本去进行内核的升级安装  ./ xxxxx        源码包安装软件:GNU  使 ...

  6. linux设置变量的三种方法

    1在/etc/profile文件中添加变量对所有用户生效(永久的) 用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久生效”. 例如:编辑/etc/ ...

  7. Linux 线程同步的三种方法(互斥锁、条件变量、信号量)

    互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...

  8. ubuntu14.04重启网卡的三种方法

    Linux重启网卡的三种方法: 一.network 利用root帐户 # service network restart 或者/etc/init.d/networking restart 二.ifdo ...

  9. linux 环境变量PATH路径的三种方法

    转:http://www.jb51.net/LINUXjishu/150167.html 总结:修改1.#PATH=$PATH:/etc/apache/bin  或者#vi /etc/profile ...

  10. Linux系统下修改环境变量PATH路径的三种方法

    这里介绍Linux的知识,比如把/etc/apache/bin目录添加到PATH中有三种方法,看完之后你将学会Linux系统下如何修改环境变量PATH路径,需要的朋友可以参考下 电脑中必不可少的就是操 ...

随机推荐

  1. C语言之基本算法39—字符串经典操作

    //字符串概念! /* ================================================================== 题目:练习字符串的 1.输入输出      ...

  2. jQuery Easy UI ProgressBar(进度条)组件

    ProgressBar(进度条)组件,这个还是挺好玩的.我们在自己做点什么的时候常常能用到,比方上传下载文件.导入导出文档啊.加载网页等等. 应用场景非常多,使用起来还非常easy. 演示样例: &l ...

  3. 荣获CCF(中国计算机学会)高级会员代表资格

    详细地址:http://www.ccf.org.cn/sites/ccf/xjhydb.jsp?contentId=2624287722908 650) this.width=650;" b ...

  4. [Angular] How to get Store state in ngrx Effect

    For example, what you want to do is navgiate from current item to next or previous item. In your com ...

  5. DOM和SAX是应用中操纵XML文档的差别

    查看原文:http://www.ibloger.net/article/205.html DOM和SAX是应用中操纵XML文档的两种主要API.它们分别解释例如以下:          DOM.即Do ...

  6. userAgent判断客户端,以及各个浏览器的ua

    userAgent判断客户端,以及各个浏览器的ua http://blog.csdn.net/yoyoosyy/article/details/70142884 navigator.userAgent ...

  7. golang API 例子实现

    golang API 例子实现 http://files.cnblogs.com/files/rojas/astaxie.zip

  8. go每个函数写代码例子

    https://github.com/astaxie/gopkg 由于目前golang的手册里面针对函数的例子太少了,很多时候不知道怎么使用,好多人都是看源代码才明白怎么用,这个给我们快速开发gola ...

  9. vue使用marked.js实现markdown转html并提取标题生成目录

    html: <template> <div class="wrapper"> <div class="container"> ...

  10. Node里面的对象创建问题

    1.利用new Object()创建时 var a =new Object() a.b = 1 console.log(a) // 打印出来是[object Object] console.log(J ...