【问题标题】:How is sleep implemented at the OS level?睡眠如何在操作系统级别实现?
【发布时间】:2010-12-15 16:47:50
【问题描述】:

我只是对sleep(time in ms) 是如何在 C 库中或基本上在操作系统级别实现感兴趣...

我猜……

  1. 可能是基于处理器速度,您执行 nop 的 while 循环(我不确定睡眠时间是否准确)...
  2. 处理器中的任何特殊寄存器,您在其中写入一些值,处理器就会停止指定时间(这将非常低效,因为处理器甚至无法运行其他程序)。

有什么线索吗?大概C库源码可以解释一下吧?我不太关心“C”是如何实现它的……我只是想知道“sleep()”函数是如何实现的。

【问题讨论】:

标签: c operating-system sleep


【解决方案1】:

Sleep() 在操作系统级别实现。当任务/线程/进程处于睡眠状态时,处理器不会旋转。该特定线程被放置在待处理队列中(线程尚未准备好运行),直到时间到期,此时线程将被放置在准备运行队列中。

同时,其他准备运行的线程也会运行。

只有当没有线程准备好运行时,操作系统才会进入空闲线程,这通常会发出指令以关闭(或无论如何进入低功耗状态)处理器,直到发生硬件中断。

仅对于一个非常简单的系统(如最简单的嵌入式系统),Sleep() 实际上可能只是一个繁忙的等待循环来实现。

任何操作系统教科书,例如 "Modern Operating Systems" by Tanenbaum 都会非常详细地介绍这一点 - 几乎所有教科书(甚至是旧的、便宜的、用过的)。

【讨论】:

  • ahhh.. 所以它不能保证在超时后唤醒.. 它取决于调度程序或系统中的其他任务...??
  • 超时后任务将在多长时间内再次运行取决于调度程序。系统可能会保证它会在超时到期后立即运行,但我认为大多数会简单地将其放在准备运行队列中的适当位置(如果线程优先级大于则可能位于最前面)任何其他),它会在下次安排时运行。
  • 许多嵌入式处理器都有专用的睡眠指令
  • @mocj -yes 在重新阅读时,我所说的关于空闲线程的内容并不像我打算停止处理器那样清楚。我希望它现在好一点。
  • 这错过了一个非常重要的解释:为什么操作系统调度程序首先有 CPU 时间来进行队列操作?选项 1:因为它在每个内核滴答声中唤醒以更新其逻辑。选项 2:因为它在 CPU 上设置了一个定时器,在确定的睡眠时间后唤醒 CPU 和操作系统。 (无滴答内核)
【解决方案2】:

您的问题的答案完全取决于操作系统和实现。

一种简单的思考方式:当您调用sleep() 时,操作系统会计算唤醒时间,然后将您的进程放在某个优先级队列中。然后,它不会安排您的进程获得任何执行时间,直到经过足够的 实时 时间才能将其从队列中弹出。

【讨论】:

    【解决方案3】:

    在典型的操作系统中,sleep 调用内核,它将进程设置为等待直到指定的时间过去,然后去寻找其他要运行的进程。如果没有更好的事情要做,它将运行“空闲进程”。一旦时间过去,调度器会注意到正在休眠的进程是好的,它会重新调度它。

    【讨论】:

    • 当然,需要注意的是Idle进程是一个运行HLT指令的进程。在现代 CPU 中,它变得非常复杂,并且根据睡眠时间的长短,它会下降到 CN 模式。 (C0 清醒,C1 短睡眠,...C7 长睡眠)
    【解决方案4】:

    你不要做任何while循环,否则系统将无法做任何事情——不响应鼠标、键盘、网络等。

    通常大多数操作系统所做的是将延迟添加到当前时间戳以获得请求延迟的任务将被恢复时的时间戳(假设当时没有更高优先级的任务运行)并添加 [wakeupTimestamp , 任务指针] 指向一个按时间戳升序排序的列表。之后,操作系统执行上下文切换并运行下一个可用任务。系统会定期将休眠列表中最早的时间戳与当前时间戳进行比较,如果截止日期已过,则将休眠任务移入“就绪”任务队列。

    【讨论】:

    • 你为什么在第二部分说一些聪明的话,而在第一部分却如此愚蠢? while 循环是可抢占的,不会中断任何鼠标事件。
    【解决方案5】:

    Sleep 在经过的时间值内阻塞您的任务/线程。在此期间,您的任务将无法运行,或者直到发生其他有趣的事情(例如信号),以较早者为准。

    sleep 调用 select() 并且不传递要等待的描述符并且超时值等于您的睡眠时间的情况并不少见。

    系统可以通过将定时器设置为在时间过去后到期,然后等待将在该定时器到期时发出信号的信号量来实现这一点。因此,它在该信号量上被阻止。

    【讨论】:

      【解决方案6】:

      cpu使用率:0%
      要求:
      create_gate(设置 IRQ 处理程序)
      pic_mask_clear(启用特定中断)
      rtc_poll(设置 RTC)
      rtc_irq
      smp_wake_up

      ; In\   RAX = Time in millisecond
      ; Out\  All registers preserved
      sleep:
          push rcx
          push rax
      
          mov rcx, [rtc_irq.up_time]
          add rax, rcx
      .os_delay_loop:
          hlt
          cmp qword [rtc_irq.up_time], rax
          jle .os_delay_loop
      
          pop rax
          pop rcx
          ret
      

      smp_wake_up

      ; In\   Nothing
      ; Out\  Nohting
      smp_wakeup_all:
          push rdi
          push rax
      
          mov rdi, [os_LocalAPICAddress]
          xor eax, eax
          mov [rdi+0x0310], eax   ; Write to the high bits first
          mov eax, 0x000C0080 ; Execute interrupt 0x80
          mov [rdi+0x0300], eax   ; Then write to the low bits
      
          pop rax
          pop rdi
          ret
      

      rtc_irq:

      ; UIP (0), RTC@32.768KHz (010), Rate@1024Hz (0110)
      ; In\   Nothing
      ; Out\  Nothing
      rtc_irq:
          inc qword[.up_time]
          call smp_wakup_all
          ret
      .up_time:       dq 0
      

      用法:

      mov rax, 1000 (millisecond)
      call sleep
      

      没问题

      【讨论】:

        猜你喜欢
        • 2011-02-10
        • 1970-01-01
        • 2017-10-27
        • 2012-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-26
        • 2016-10-12
        相关资源
        最近更新 更多