linux 系统下的休眠应用

         linux 系统下的休眠函数主要有两个,sleep,nanosleep;usleep 已经被遗弃;sleep,nanosleep休眠都是基于实时时钟(比如挂钟,墙钟,手表,国家授时时间)的sleep,两种sleep方式都受信号中断影响,调用进程捕捉到一个信号并从信号处理程序返回(nanosleep返回未休眠完的秒数)。信号会对所在进程产生中断,同时sleep退出,比如SIGALRM,或系统通知进程的信号,都会导致sleep的退出,导致没有达到相关的预期。

       直接使用sleep,nanosleep需要考虑中断的因素,避免和定时器的SIGALRM冲突,减少sleep的中断,定时器避免使用
ITIMER_REAL(SIGALRM)方式和ITIMER_PROF(SIGPROF),尽量采用ITIMER_VIRTUAL方式。

     另外采用退出继续sleep的方法:

void myMsleep(unsigned int mSec)
{
   unsigned int interrupt_cnk = 0;
   struct timespec req = {0};
   req.tv_sec  =  mSec / 1000;
   req.tv_nsec = (mSec % 1000) * 1000000;
    while (nanosleep(&req, &req) < 0 && errno == EINTR)
    {
        if(errno == EINTR)
        {
         interrupt_cnk ++;
        }	
    }
    if(interrupt_cnk > 0)
    {
      printf("myMsleep[%d]ms interruupt_cnk:%d\n",mSec,interrupt_cnk);	
    }
}

 

      随着多系统时钟的引入,我们需要一种方法来挂起调用线程,使用一个运行时钟来实现一段延时,函数clock_nanosleep实现了这一功能,解决被中断退出的问题。

int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *reqtp, struct timespec *remtp);
参数clock_id用于指定延时是相对于哪一种时钟时间进行的评估。参数flags用于控制延时是绝对的还是相对的,
当flags被设置为0的时候,睡眠时间是相对的,当其数值被设置为TIMER_ABSTIME的时候,睡眠时间是绝对的,直到时钟到达指定的时间才返回。
当设置为绝对延时参数remtp是没有被使用的。参数reqtp以及remtp,与函数nanosleep相同。

CLOCK_REALTIME:实时系统时钟,以相对时间为准,从1970.1.1到目前的时间,更改系统时间会更改获取的值,硬件定时中断产生。
CLOCK_MONOTONIC:实时系统时钟,以绝对时间为准,获取的时间为系统重启到现在的时间,更改系统时间对它没有影响硬件定时中断产生。
CLOCK_PROCESS_CPUTIME_ID:系统运行时钟,运行周期计时。
CLOCK_THREAD_CPUTIME_ID:线程运行时钟,运行周期计时。

调用clock_nanosleep(CLOCK_REALTIME, 0, reqtp, remtp);
与如下调用有着完全相同的作用
nanosleep(reqtp, remtp);

可以使用while(clock_nanosleep(CLOCK_PROCESS_CPUTIME_ID,0,&req, &req)< 0 && errno == EINTR) 或

while(clock_nanosleep(CLOCK_MONOTONIC,0,&req, &req)< 0 && errno == EINTR)替代nanosleep用例,

但是由于CLOCK_PROCESS_CPUTIME_ID是进程的可运行时钟周期,所以本进程不能进入休眠状态,并且由于本进程的CPU调度关系,所以期望和预设的值差别比较大!也需要慎用!

测试发现,休眠没有被定时中断退出的情况。

休眠的另一种方式线程等待:pthread_cond_timedwait

int threadSleep(unsigned int msec) 
{
  pthread_cond_t cond;
  pthread_mutex_t mutex;
  pthread_condattr_t cattr; 
  struct timeval now;
  struct timespec waittime;
  int ret = -1;
  long nsec = 0;
  
  pthread_mutex_init(&mutex, NULL);
  pthread_condattr_init(&cattr);
  pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
  pthread_cond_init(&cond, &cattr);
  
  clock_gettime(CLOCK_MONOTONIC, &waittime);
  nsec = waittime.tv_nsec + (msec * 1000) * 1000; 
  waittime.tv_sec += nsec / 1000000000;
  waittime.tv_nsec = nsec % 1000000000; 
  
  pthread_mutex_lock(&mutex);
  ret = pthread_cond_timedwait(&cond, &mutex, &waittime);
  pthread_mutex_unlock(&mutex);
  return ret;
}

注意:特别小心使用CLOCK_REALTIME方式休眠,避免因为系统调整时间回退导致的无法退出的问题;另外在while或for的死循环里,需要考虑内核系统运行调度周期,尽量避免nanosleep小于这个周期,导致系统高频率的运行调度导致的CPU的性能损耗。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值