linux___定时器__延时____操作

1,linux的关于时间的几个结构体:

1、时间类型。Linux下常用的时间类型有4个:time_t,struct timeval,struct timespec,struct tm。
(1)time_t是一个长整型,一般用来表示用1970年以来的秒数。
(2)Struct timeval有两个成员,一个是秒,一个是微妙
struct timeval {
               long tv_sec;        /* seconds */
               long tv_usec;  /* microseconds */
       };
(3)struct timespec有两个成员,一个是秒,一个是纳秒。
struct timespec{
                      time_t  tv_sec;         /* seconds */
                      long    tv_nsec;        /* nanoseconds */
              };
(4)struct tm是直观意义上的时间表示方法:
struct tm {
                      int     tm_sec;         /* seconds */
                      int     tm_min;         /* minutes */
                      int     tm_hour;        /* hours */
                      int     tm_mday;        /* day of the month */
                      int     tm_mon;         /* month */
                      int     tm_year;        /* year */
                      int     tm_wday;        /* day of the week */
                      int     tm_yday;        /* day in the year */
                      int     tm_isdst;       /* daylight saving time */
              };

2,简单的定时器:



//定时器的使用:
//2.1,linux中如果在一个进程中只需要一个定时器的话,如果有多个定时器这个就不可以用了就可以采用setitimer函数的形式来做。如下
#include <stdio.h>    
#include <unistd.h>   
#include <signal.h>   
#include <string.h>   
#include <sys/time.h> 
void printMsg(int);
static void createTimer()
{  
int res = 0;
  struct itimerval tick;
  signal(SIGALRM, printMsg);
  memset(&tick, 0, sizeof(tick));
  tick.it_value.tv_sec = 2; 
  tick.it_value.tv_usec = 0;
  tick.it_interval=tick.it_value; 
  res = setitimer(ITIMER_REAL, &tick, NULL);
  if (res) 
 {
    printf("Set timer failed!!/n");
  }
  else
  printf("timer is running...\n");
}
static void stopTimer()
{
int res = 0;
struct itimerval tick;
tick.it_value.tv_sec = 0;  
  tick.it_value.tv_usec = 0; 
  tick.it_interval=tick.it_value; 
 res = setitimer(ITIMER_REAL, &tick, NULL);
  if (res) 
 {
    printf("Set timer failed!!/n");


  }
  else
  printf("timer is stop...\n");
 
  
}
int main() 
{
createTimer();
getchar();
 stopTimer();
 
 
while(1){
sleep(2);
}




  return 0;  


}


void printMsg(int num) {

  printf("Hello World!!\n");

}

2.2 在一个程序中使用多个定时器的程序,可以任意时刻开启,任意时刻关闭,超时处理,采用的是select +pipe的形式

这样做即安全,有高效,不必影响linux的信号处理服务。

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>


int fdctl[2];// 这个管道在建立线程之前建立。创建线程之后,两个线程各连接其中一端。因为不存在 fork 导致的 fd 复制,所以不需要像普通多进程环境一样 close 一端
void *createTimer(void *arg)
{
   int timecnt=0;   
    
   fd_set rdset;
 struct timeval tv;
   tv.tv_sec = 0;  
  tv.tv_usec =500*1000; 
  int maxfd ;
  int ret;
 pthread_detach(pthread_self());
 
  pipe( fdctl);
  maxfd = fdctl[1];


   while(1)   
   {
     FD_ZERO( &rdset );
      FD_SET( fdctl[1], &rdset ); // 控制管道。虽然 close 管道一端会同时引发 readable / writable 事件,但是由于 pipe 有缓冲,默认情况下 pipe 就是 writable 的,所以使用 rdset 进行监测
      tv.tv_sec = 0;  
      tv.tv_usec =500*1000; 
      ret= select( maxfd + 1, &rdset, NULL, NULL, &tv ); 
      printf( "select() returned with %d\n", ret );
      if(ret == 1) 
        {
          if ( FD_ISSET( fdctl[1], &rdset ) )
          {
            printf( "Ctrled Exit\n" );
               break;
          }
        }
        else if(ret==0)  ///timeout
        {
          fprintf(stderr,"timeout.....!\n");
        }
   }
    fprintf(stderr,"break;\n"); 
    return NULL;
}
void libck_createTimerAndStart(void)
{
 pthread_t timeid;   
    pthread_create(&timeid, NULL, &createTimer, NULL);  
  
}
void stopTimer()
{
close( fdctl[0] );// 当一个 fd 被关闭的时候,会触发 readable / writable 事件
}
int main()
{
int i;
libck_createTimerAndStart();

 
  for ( i = 0; i < 5; ++i )
  {
       sleep( 1 );
      printf( "%d sec\n", i );
    }
  stopTimer();  
  sleep(1);  ///等待退出
return 0;
}

3, 关于延时函数:

没有测试过,只是看别人这么说:linux中sleep 和select 这些函数在延时的时候,不阻塞别线程切换,而usleep是阻塞的, 如果这样的话,想延时的时候小于1s应该怎么办,
可以采用如下的形式:
void sno_Delay(unsigned int ms)
{
    int was_error;
    
    struct timespec elapsed, tv;
        
    elapsed.tv_sec = ms / 1000;
    elapsed.tv_nsec = (ms % 1000) * 1000000;
    do 
    {
        errno = 0;
        tv.tv_sec = elapsed.tv_sec;
        tv.tv_nsec = elapsed.tv_nsec;
        was_error = nanosleep(&tv, &elapsed);


    }while (was_error && (errno == EINTR));

}

1031号更新的:------------------------------------

sleep ,usleep ,nanosleep的区别
可以man一下:发现
man sleep :  描述是:sleep()  makes  the  calling  process  sleep 暂时理解为使进程休眠。
man usleep: 描述是: The usleep() function suspends execution of the calling process for (at least) usec microseconds. 理解为也是使进程休眠
man nanosleep: 描述是:nanosleep()  suspends  the execution of the calling thread 使线程休眠。
扩展出的几个函数:
void delay_ms(unsigned int ms)
{
    int was_error;
    
    struct timespec elapsed, tv;
        
    elapsed.tv_sec = ms / 1000;
    elapsed.tv_nsec = (ms % 1000) * 1000000;
    do 
    {
        errno = 0;
        tv.tv_sec = elapsed.tv_sec;
        tv.tv_nsec = elapsed.tv_nsec;
        was_error = nanosleep(&tv, &elapsed);

    }while (was_error && (errno == EINTR));
}
void delay_us(unsigned int us)
{
int was_error;
    
    struct timespec elapsed, tv;
        
    elapsed.tv_sec = us / 1000000;
    elapsed.tv_nsec = (us % 1000000) * 1000000000;
    do 
    {
        errno = 0;
        tv.tv_sec = elapsed.tv_sec;
        tv.tv_nsec = elapsed.tv_nsec;
        was_error = nanosleep(&tv, &elapsed);

    }while (was_error && (errno == EINTR));
}
///以下转自 http://blog.csdn.net/learnhard/article/details/5699505 
SIGINT信号导致的usleep无效问题
如果你的程序有多个无限循环的子线程(周期性地完成某一任务),
当程序结束的时候,为了能够优雅地退出这些线程,通常都会先在子线程的while()无限循环中,设置一个(全局)运行标志,例如:
while (g_flag)
{
/
// do something periodically 
/
usleep(1000000); // sleep for 1 second 
}
然后,在主线程中可以注册一个信号处理函数,在该函数中改变全局变量g_flag的值为false,
这样,向程序发送一个信号的时候,就可以使得子线程的运行标志改变,从而退出,然后程序也就可以退出了。
可是这样做的问题是:
今天发现一个问题,在为SIGINT信号注册的处理函数中,改变了全局运行标志的值,程序却依然没有退出,
究其原因,发现是子线程中使用的usleep函数与触发的信号发生了一段缠绵悱恻的爱情,从而导致神经错乱,然后就不正常了。 


其实我们应该使用精度更高的nanosleep()函数,当然追求的并不一定是精度,而是使程序能正常运行。man nanosleep可见如下说明:
Compared to sleep(3) and usleep(3), nanosleep() has the advantage of not affecting any signals, it is standardized by POSIX, 
it provides higher timing resolution, and it allows to continue a sleep that has been interrupted by a signal more easily.


所以,尽量使用nanosleep函数来完成无限循环中的休眠任务,而不是用usleep()或sleep()。
改为使用nanosleep之后,发现程序正常了,可以优雅地退出各个子线程,然后再退出整个程序。


如果想更精确的延时,可以采用select来做。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值