什么是 RTOS 内核锁定以及何时需要使用它?

What is RTOS Kernel Locking and When Do You Need to Use It?

我正在使用 ChibiOS RTOS,我有一些看似基本的问题,但我有点想不通。

ChibiOS 有一个函数叫做:

chSysLock();

chSysUnlock();

据我了解,这两个函数将分别锁定和解锁内核。

所以我的问题是:

  1. 锁定内核有什么作用?
  2. 为什么要锁定内核?

最后,让我们使用这个例子:

static void sem_cb(void) {
    chSysLock();
    chBSemSignalI(&sem_1);
    chSysUnlock();
}

这个函数只是为正在等待它的线程发送信号量。

所以我的最后一个问题是:

  1. 锁定内核只是为了发出信号量有什么意义?如果我不这样做,那么 ChibiOS 会抱怨并且在没有系统锁定的情况下不会编译。

一般来说,在 RTOS 内核中,调度程序不会简单地锁定 运行,因此不会发生上下文切换。通常也会禁用一些或所有中断。锁定用于关键部分 - 必须 运行 没有中断或抢占的代码部分。

我不是 ChibiOS 方面的专家,但在这方面似乎有点 over-complicated 并且没有非常全面的文档。内核状态描述为 here。它有两种锁定模式,chSysLock()调用S-Locked状态,其中

"Kernel locked and regular interrupt sources disabled. Fast interrupt sources are enabled. S-Class and I-Class APIs are invokable in this state."

从文档中不清楚这是否意味着可以使用 I/S-Class API 或 I/S-mode APIs 只能在锁定时调用。整个状态及其目的在 IMO 中没有明确定义。然而,在某些 RTOS 中通常有不调用调度程序的特殊版本的函数,这可以节省常规 API 函数的检查内核状态或中断上下文的开销,并且是一个较小的优化(在我认为以安全为代价)。 chBSemSignalI:

的文档证实了这一点

Note

This function does not reschedule.

[...]

Function Class:

This is an I-Class API, this function can be invoked from within a system lock zone by both threads and interrupt handlers.

在您的示例中,正在发生的是给出了信号量,但调度程序不会运行,因此不会立即使任何等待的线程就绪。目前尚不清楚 chSysUnlock() 是否导致调度程序 运行 - 文档说“特殊功能,此功能有特殊要求见注释。”,但给出不知道在哪里可以找到这些笔记。

我希望调度程序 运行,从表面上看,函数 sem_cb() 似乎没什么用;但是我也希望 chSysLock()/chSysUnlock() 是可嵌套的,在这种情况下函数的目的更有意义。无论内核状态如何,它都允许使用单个 semaphore-give 函数 (sem_cb())。也就是说,在正常和 S-State 中调用是安全的,但会增加单独的 S-State/Normal 状态 API 旨在避免的开销。就我个人而言,我总是为了安全起见(尽管不一定以这种方式实施),至少直到可以证明开销是不可接受的为止。它本质上是说“_give 信号量,如果内核未锁定,则重新安排,否则推迟重新安排,直到内核解锁 - 即在最后一次嵌套 unlock 之后”。

但是,它不允许从中断上下文中调用 sem_cb(),因为这需要 chSysLockFromISR()

以上根据文档和 "expected" RTOS 行为做出了很多假设。如果我碰巧在面对如此匮乏的文档时使用 ChibOS,我会检查源代码以确定确切的行为。