• sleep(0)、usleep(0)与sched_yield() 调度


    结论:

      如果你是为了耗掉一个机器周期 ,那直接asm ("nop") ,

      如果是为了让权,建议把 所有使用 usleep(0)  换成 sched_yield() ;


     

     

    最近发现很多hpc 领域的MPI程序中在用usleep(0) ,比较差异。 后来问了之前做hpc 的同事 得到的答复是

    一般用usleep(0) 的主要目的应该是:

    CPU交出当前线程的执行权,让CPU去执行其他线程。也就是放弃当前线程的时间片,转而执行其他线程

     

    我感觉很诧异。 Usleep(0) 来做这个事情 是POSIX要求的 还是一个意外的发现呢?

    于是有2个问题 

    1 :usleep(0) 能不能让权, 

    :如果可以,那么和sched_yield 比到底谁更合适

     

    我先man了一下usleep(0) 在linux上 , 

    NOTES
           The type useconds_t is an unsigned integer type capable of holding integers in the range [0,1000000].  Programs will be  more
           portable if they never mention this type explicitly.  Use
    
               #include <unistd.h>
               ...
                   unsigned int usecs;
               ...
                   usleep(usecs);
    
           The  interaction  of  this  function  with  the  SIGALRM  signal,  and with other timer functions such as alarm(2), sleep(3),
           nanosleep(2),  setitimer(2),  timer_create(2),  timer_delete(2),  timer_getoverrun(2),  timer_gettime(2),   timer_settime(2),
           ualarm(3) is unspecified.

     

    先来看几个奇怪的现象:


     执行shell usleep 0 会明显的看到调用了


     难道 

    usleep(0) = sched_yield? 

     


     执行shell usleep x (x!=0 ) 会去调用naonsleep



    这就比较合理了,  之前猜测 usleep  就应该是调用了 nanosleep ,

     

    然后写一个 c 函数调用来看看 

    会发现 无论是0  还是 !0 都是调用的



     

    这就比较合理了, 看了glibc源码 也验证了确实是 封装naosleep 

     

    那第一个问题在linux 上就变成 naosleep(0,0) 是不是会去让权了, 他和sheld_yield 的区别。 

     

    .18 之后 应该naosleep 都是基于 hrtimer的机制实现了 (

    ============================================================== 

    C代码 

    do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)

    1. {  
    2. hrtimer_init_sleeper(t, current);  
    3. do {  
    4. set_current_state(TASK_INTERRUPTIBLE);  
    5. hrtimer_start_expires(&t->timer, mode);  
    6. if (!hrtimer_active(&t->timer))  
    7. t->task = NULL;  
    8. if (likely(t->task))  
    9. schedule();  
    10. hrtimer_cancel(&t->timer);  
    11. mode = HRTIMER_MODE_ABS;  
    12. while (t->task && !signal_pending(current));  
    13. __set_current_state(TASK_RUNNING);  
    14. return t->task == NULL;  
    15. }  

     =======

    补充一个 在2.6.9内核 或者可能之前的glibc实现中 usleep(0) 如果是基于 select (0) 这样的实现  

    在判断入参是0 之后会离开返回 不会调用 schelduer()的 

     

      

     

    =====================================================================

     

    )

     

    根据nanosleep 的 syscall ,发现

     

     

    很明显的有 schedule(), 于是可以确定 usleep(0) 如果一切顺利确实会让权,那么和sched_yield比呢 

     

    于是写了一个 main 

     

     

    C代码  收藏代码
    1. #include <unistd.h>  
    2. #include <sched.h>  
    3. int main(){  
    4. int j ;  
    5. for(j=0; j<100000; j++)  
    6. //usleep(0);  
    7. sched_yield();  
    8. }  

     

     

    sched_yield() 的时候 调用10万次 的耗时如下


     

     

    usleep(0) 的时候 调用10万次 的耗时如下

     


     

     

    延迟简直不是一个数量级。。 太可怕了,如果用于网络 那要丢多少UDP , TCP要做多少次拥塞避免。

     

     

    在来看一下MPI中的这个问题


     http://trac.mcs.anl.gov/projects/mpich2/ticket/1597

     

    MPI有个Yield宏,使用了 usleep(0) ,但是比较大的延迟

    最后一张表的意思是, 应该尽可能的让CPU 100%,这样才算是yield。。

     

     

     

    那为什么会造成usleep 如此延迟呢? 

    先看一下  trace的信息

    Usleep 

     

    非常可怕  因为是非主动让权 调用了 deactivate_task()有简单操作系统知识的都知道

    简直就恶魔。。。


     

    然而 sched_yield()


    非常干净  简直perfect! 

     

     

     

    我们知道 在hpc 领域 MPI 的终极目地 就是耗尽CPU 

    usleep(0) 这么高的延迟 肯定是不能用来做让权的。 而且我也不觉得 usleep(0) 可以用在任何地方 ,这是一个没保证,(你知道哪天glibc改了呢) 和极其不高效的方式 。

    如果你是为了耗掉一个机器周期 ,那直接asm ("nop") ,如果是为了让权建议所有使用usleep(0) (注意是0,不是其他)的地方换成 sched_yield() ;

  • 相关阅读:
    iOS中的UISearchBar
    iOS中的UIDatePicker 日期选择器
    iOS中的 深拷贝和浅拷贝
    iOS中的定时器实现图片的轮播
    iOS Crash文件的解析(一)
    iOS中的UIToolBar
    iOS中的瀑布流(RootCollectionViewControlle)
    iOS中NSThread(主线程,子线程)
    iOS中的串行,并行,分组,一次,障碍,延迟,反复执行(GCD)
    iOS中的动画
  • 原文地址:https://www.cnblogs.com/schips/p/11002589.html
Copyright © 2020-2023  润新知