【问题标题】:How scheduler knows a Task is in blocking state?调度程序如何知道任务处于阻塞状态?
【发布时间】:2016-12-21 02:23:57
【问题描述】:

我正在阅读 David E.Simon 的“嵌入式软件入门”。 其中讨论了 RTOS 及其构建块调度程序和任务。它表示每个任务要么处于就绪状态,要么处于运行状态,要么处于阻塞状态。我的问题是调度程序如何确定任务处于阻塞状态?假设它正在等待一个信号量。那么信号量很可能处于无法返回的状态。调度器是否查看一个函数是否没有返回,然后将其状态标记为阻塞?

【问题讨论】:

  • 信号量和while循环?这是等待同步原语的不寻常方式......
  • 我的意思是 Semaphore 的实现是一个 while() 循环。我将编辑问题。
  • 您要问的实际上是一个实现细节,对 RTOS 的一般工作方式没有真正的兴趣。有几种方法可以实现这一点,选择可能取决于代码大小限制、可用 RAM(例如,非常小的 micros)、整体性能等。例如,当给定信号量不可用时,任务被标记为阻塞在试图得到它。或者,当信号量不可用时,只需让步到下一个任务(隐式将其标记为阻塞)以在下一个任务切片重试,直到最终信号量可用(可怜的版本)。

标签: rtos


【解决方案1】:

实施细节会因 RTOS 而异。通常,每个任务都有一个状态变量,用于标识任务是就绪、运行还是阻塞。调度器只是简单地读取任务的状态变量来判断任务是否被阻塞。

每个任务都有一组参数来确定任务的状态和上下文。这些参数通常存储在结构中并称为“任务控制块”(尽管实现因 RTOS 而异)。就绪/运行/块状态变量可能是任务控制块的一部分。

当任务尝试获取信号量并且信号量不可用时,任务将被设置为阻塞状态。更具体地说, semaphore-get 函数会将任务从运行变为阻塞。然后将调用调度程序来确定接下来应该运行哪个任务。调度器会读取任务状态变量,不会运行那些被阻塞的任务。

当另一个任务最终设置信号量时,被阻塞在信号量上的任务将从阻塞状态变为就绪状态,并且可能会调用调度程序来确定是否应该发生上下文切换。

【讨论】:

    【解决方案2】:

    当我正在编写 RTOS (http://distortos.org/) 时,我想我可以插话。

    保存每个线程状态的变量确实通常在 RTOS 中实现,这包括我的版本: https://github.com/DISTORTEC/distortos/blob/master/include/distortos/ThreadState.hpp#L26 https://github.com/DISTORTEC/distortos/blob/master/include/distortos/internal/scheduler/ThreadControlBlock.hpp#L329

    但是,此变量通常仅用作调试辅助或额外检查(例如阻止您启动已启动的线程)。

    在针对深度嵌入式系统的 RTOS 中,就绪/阻塞之间的区别通常是使用容纳线程的容器来区分的。通常线程在链表中“链接”,通常也按优先级和插入时间排序。调度程序有自己的“就绪”线程列表(https://github.com/DISTORTEC/distortos/blob/master/include/distortos/internal/scheduler/Scheduler.hpp#L340)。每个同步对象(如信号量)也有自己的线程列表,这些线程“阻塞”等待该对象(https://github.com/DISTORTEC/distortos/blob/master/include/distortos/Semaphore.hpp#L244)。当线程尝试使用当前不可用的信号量时,它只是从调度程序的“就绪”列表移动到信号量的“阻塞”列表(https://github.com/DISTORTEC/distortos/blob/master/source/synchronization/Semaphore.cpp#L82)。调度器不需要决定任何事情,因为现在——从调度器的角度来看——这个线程已经消失了。当这个信号量现在被另一个线程释放时,在这个信号量的“阻塞”列表中等待的第一个线程被移回调度程序的“就绪”列表(https://github.com/DISTORTEC/distortos/blob/master/source/synchronization/Semaphore.cpp#L39)。

    通常不需要特别区分准备好的线程和实际运行的线程。由于可以实际运行的线程数量是固定的并且等于可用 CPU 内核的数量,因此您只需要一个指针,指向每个 CPU 内核的指针,该指针指向在该内核上运行的“就绪”列表中的线程那一刻。在我的系统中,我也是这样做的——位于“就绪”列表头部的线程是正在运行的线程,但我还管理一个指向该线程的迭代器(https://github.com/DISTORTEC/distortos/blob/master/include/distortos/internal/scheduler/Scheduler.hpp#L337)。您可以为正在运行的线程设置一个单独的列表,但在大多数情况下,这会浪费空间(通常只有一个)并且会使其他事情稍微复杂一些。

    如果您有兴趣,我实际上已经写了一篇关于线程状态及其转换的文章 - http://distortos.org/documentation/task-states/ 这篇文章没有特别区分“就绪”线程和实际运行的线程。我不认为这种区别实际上对任何事情都有用,只要您有其他方法来判断哪些“就绪”线程正在运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-27
      • 2023-03-20
      • 2019-11-21
      • 1970-01-01
      相关资源
      最近更新 更多