Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3883041
  • 博文数量: 146
  • 博客积分: 3918
  • 博客等级: 少校
  • 技术积分: 8585
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-17 13:52
个人简介

个人微薄: weibo.com/manuscola

文章分类

全部博文(146)

文章存档

2016年(3)

2015年(2)

2014年(5)

2013年(42)

2012年(31)

2011年(58)

2010年(5)

分类: LINUX

2011-12-03 13:05:17

    Heartwork前辈在我前一篇博文多线程条件下的计数器(2)中的回复中提到,

nanosleep的问题很好解释,看这里……

    The nanosleep() function shall cause the current thread to be suspended from execution until either the time interval specified by the rqtp argument has elapsed or a signal is delivered to the calling thread, and its action is to invoke a signal-catching function or to terminate the process. The suspension time may be longer than requested because the argument value is rounded up to an integer multiple of the sleep resolution or because of the scheduling of other activity by the system. But, except for the case of being interrupted by a signal, the suspension time shall not be less than the time specified by rqtp, as measured by the system clock CLOCK_REALTIME.

    The use of the nanosleep() function has no effect on the action or blockage of any signal.

简单来说,这个误差是与调度器的时间片和调度策略有关的,也就是可以通过减小时间片大小和使用实时性更好的调度策略(比如SCHED_RR)来获得更小的分辨率。

下来我写了段测试代码,对默认情况和设置调度算法后的nanosleep做了测量。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/time.h>
  5. #include<sched.h>

  6. #define COUNT 10000
  7. #define MILLION 1000000L
  8. #define NANOSECOND 1000

  9. int main(int argc,char* argv[])
  10. {
  11.         int i;
  12.         struct timespec sleeptm;
  13.         long interval;
  14.         struct timeval tend,tstart;

  15.         struct sched_param param;

  16.         if(argc != 2)
  17.         {
  18.          fprintf(stderr,"usage:./test sched_method\n");
  19.                 return -1;
  20.         }
  21.         int sched = atoi(argv[1]);
  22.         param.sched_priority = 1;
  23.         sched_setscheduler(getpid(),sched,&param);

  24.         int scheduler = sched_getscheduler(getpid());
  25.         fprintf(stderr,"default scheduler is %d\n",scheduler);

  26.         sleeptm.tv_sec = 0;
  27.         sleeptm.tv_nsec = NANOSECOND;

  28.         if(gettimeofday(&tstart,NULL)!=0)
  29.         {
  30.                 fprintf(stderr,"get start time failed \n");
  31.                 return -2;
  32.         }

  33.         for(i = 0;i<COUNT;i++)
  34.         {
  35.                 if(nanosleep(&sleeptm,NULL) != 0)
  36.                 {
  37.                  fprintf(stderr,"the %d sleep failed\n",i);
  38.                      return -3;
  39.                 }
  40.         }

  41.         
  42.         if(gettimeofday(&tend,NULL)!=0)
  43.         {
  44.            fprintf(stderr,"get end time failed \n");
  45.            return -4;
  46.         }

  47.         interval = MILLION*(tend.tv_sec - tstart.tv_sec)
  48.                    +(tend.tv_usec-tstart.tv_usec);

  49.         fprintf(stderr,"the expected time is %d us,but real                                   time cost is %lu us\n",COUNT,interval);

  50.         return 0;
  51. }
  1. root@libin:~/program/C/timer# ./test 0
  2. default scheduler is 0
  3. the expected time is 10000 us,but real time cost is 630624 us
  4. root@libin:~/program/C/timer# ./test 1
  5. default scheduler is 1
  6. the expected time is 10000 us,but real time cost is 67252 us
  7. root@libin:~/program/C/timer# ./test 2
  8. default scheduler is 2
  9. the expected time is 10000 us,but real time cost is 82449 us

所谓调度算法值 0 1  2 分别是什么呢?bit/sched.h中定义:

  1. #define SCHED_OTHER 0
  2. #define SCHED_FIFO 1
  3. #define SCHED_RR 2
  4. #ifdef __USE_GNU
  5. # define SCHED_BATCH 3
  6. #endif
从结果上看,采用默认的算法是SCHED_OTHER nanosleep是最不准确的,理想情况下,每次睡1us,睡10000次,耗时因该是10ms,实际上耗时是630ms。采用时间片轮转的SCHED_RR nanosleep的计时 要准确一些,耗时为82ms.依次类推。


至于调度算法如何影响nanosleep,我还不是很清楚,里面还有很多东西需要我继续学习。好久没写博客了,先将这篇不成熟的博文拿出,抛砖引玉。

参考文献:
1 UNIX 系统编程
2 Heartwork的回复













阅读(8557) | 评论(3) | 转发(1) |
给主人留下些什么吧!~~

Heartwork2011-12-05 13:36:45

前辈不敢当,我也只是个工作不满五年的本科生而已。仁兄写的东西比较对我的胃口,所以常常过来砸场子,勿怪哈~

更正:以上提到的影响nanosleep的因素应该是时钟中断频率和调度策略。

简单描述一下这两个因素对于定时器的影响。
1) 时钟中断频率:
在中断返回时内核会对检查一个need_resched的标志位来决定是否需要重新调度,提高时钟频率就可以让内核及早发现可执行的进程。

2)调度策略
使用实时的调度策略是为了赋予进程较高的优先级,保证内核在进程调度时会被首先选中。(内核总是选择优先级最高的进程)

具体可以参考Linux Kernel Development的调度和定时器的章节。

GFree_Wind2011-12-04 23:37:40

如果我没有记错的话,SCHED_FIFO和SCHED_RR是实时进程的调度策略。如果设置成这两个,应该会把进程设置为了实时进程。所以nanosleep才更准确的。但是,个人认为,不应该有太多的实时进程。