概念

使CPU空闲会导致内核暂停所有操作,直到事件(通常是中断)唤醒CPU。在常规系统中,idle线程负责此操作。但是,在某些受约束的系统中,可能是另一个线程承担此职责。

实现

使CPU空闲

使CPU空闲很简单:调用k_cpu_idle()API。CPU将停止执行指令,直到事件发生。最有可能的是,该函数将在循环中调用。

请注意,在某些体系结构中,在k_cpu_idle()返回时将无条件的解除中断。

  1. static k_sem my_sem;
  2. void my_isr(void *unused)
  3. {
  4. k_sem_give(&my_sem);
  5. }
  6. void main(void)
  7. {
  8. k_sem_init(&my_sem, 0, 1);
  9. /* wait for semaphore from ISR, then do related work */
  10. for (;;) {
  11. /* wait for ISR to trigger work to perform */
  12. if (k_sem_take(&my_sem, K_NO_WAIT) == 0) {
  13. /* ... do processing */
  14. }
  15. /* put CPU to sleep to save power */
  16. k_cpu_idle();
  17. }
  18. }

原子方式使 CPU 空闲

在使CPU空闲之前,可能需要以原子方式执行一些工作。在这种情况下,应改用k_cpu_atomic_idle()
实际上,在前面的示例中存在一个争用条件:中断可能发生在获取信号量获取和使CPU再次空闲之间。在某些系统中,这可能会导致CPU空闲,从而完全挂起系统。为了防止这种情况,应该使用k_cpu_atomic_idle(),如本例所示。

  1. static k_sem my_sem;
  2. void my_isr(void *unused)
  3. {
  4. k_sem_give(&my_sem);
  5. }
  6. void main(void)
  7. {
  8. k_sem_init(&my_sem, 0, 1);
  9. for (;;) {
  10. unsigned int key = irq_lock();
  11. /*
  12. * Wait for semaphore from ISR; if acquired, do related work, then
  13. * go to next loop iteration (the semaphore might have been given
  14. * again); else, make the CPU idle.
  15. */
  16. if (k_sem_take(&my_sem, K_NO_WAIT) == 0) {
  17. irq_unlock(key);
  18. /* ... do processing */
  19. } else {
  20. /* put CPU to sleep to save power */
  21. k_cpu_atomic_idle(key);
  22. }
  23. }
  24. }