首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

关于linux下的定时函数的一些认识解决思路

2012-04-25 
关于linux下的定时函数的一些认识今天看书看到了关于alarm的一些用法,自己有在网上找了些资料看了下;1。ala

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

C/C++ code
#include <stdio.h>#include <unistd.h>#include <signal.h>void sigalrm_fn(int sig){    printf("alarm!\n");    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信号:
C/C++ code
#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 \n");            signal(SIGALRM, sigroutine);            break;        case SIGVTALRM:            printf("Catch a signal -- SIGVTALRM \n");            signal(SIGVTALRM, sigroutine);            break;    }    return;}int main(){    struct itimerval value, ovalue, value2;          //(1)    sec = 5;    printf("process id is %d\n", 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.
Linux下的微秒级定时器: usleep, nanosleep, select, pselect 


C/C++ code
#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\n", "fuction", "time(usec)", "realtime", "reduce");      fprintf(stderr, "----------------------------------------------------\n");      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]\n", 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, "\t usleep       %8u   %8u   %8d\n", 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, "\t nanousleep   %8u   not support\n", nDelay);           }           gettimeofday(&tvNow, NULL);           nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;           nReduce = nTimeTest - nDelay;           fprintf (stderr, "\t nanosleep    %8u   %8u   %8d\n", 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]\n", 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, "\t select       %8u   %8u   %8d\n", 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]\n", 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, "\t pselect      %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);             fprintf (stderr, "--------------------------------\n");        }            return 0;  }   


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

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

总结:alarm属于定时精准比较差的,是基于信号的SIGALRM的(此信号系统默认是终止进程,使用时应该先定义signal,看百度上介绍这种定时要被淘汰……),setitimer定时精准,但是能使用的数量少,最多3个(3种类型)(UNIX当时怎么不多定义几个像windows下的SETTIMER一样),而usleep, nanosleep, select, pselect 
则可无限使用,关键看是否需要线程切换,

[解决办法]
恩,linux下多定时器都是通过单定时器模拟的
[解决办法]
哥哥写得不错,加油!

热点排行