使用抢占式内核时的信号量

Semaphore when using a pre-emptive kernel

我知道二进制信号量是什么:当中断的 ISR 将其设置为 1 时,它是一个标志。

但是,当我们使用抢占式内核(例如 FreeRTOS)时,什么是信号量?和二进制信号量一样吗?

it is a flag when is set to 1 by an ISR of an interrupt.

这对信号量的描述既不完整也不准确。您所描述的只是一个标志。信号量是一个同步对象;典型的实时操作系统提供三种形式:

  • 二进制信号量
  • 计数信号
  • 互斥信号量(Mutex)

在二进制信号量的情况下,有两个操作givetake。获取信号量的任务将阻塞(即暂停执行并允许其他优先级较低或相同的线程运行线程运行)直到其他线程或中断处理程序给出信号量。二进制信号量用于在线程之间以及从 ISR 到线程的信号量。它们通常用于实现 延迟中断处理程序 ,因此 ISR 可以非常短,并且处理程序受益于 ISR 中不允许的 RTOS 机制(任何阻止或暂停执行的东西) ).

多个线程可能会阻塞在一个信号量上,但只有其中一个任务会响应获取信号量。一些 RTOS 有一个 flush 操作(例如 VxWorks),它将所有等待信号量的线程同时置于 ready 状态 - 在这种情况下它们将运行根据优先级调度方案。

一个Counting Semaphore类似于一个Binary Semaphore,只是它可以被赋予多次,而且tasks可以拿这个semaphore在计数为零之前不阻塞。

A Mu​​tex 用于资源锁定。可以为此使用二进制信号量,但互斥锁提供的功能可以使它更安全。对互斥量的操作是 lockunlock。当一个线程锁定一个互斥量,而另一个任务试图锁定同一个互斥量时,第二个(和任何后续的)任务将阻塞,直到第一个任务将其解锁。这可用于防止多个线程同时访问资源(内存或 I/O)。一个线程可能多次锁定一个互斥体;维护一个计数,因此在释放锁之前它必须被解锁相同的次数。这允许线程嵌套锁。

互斥锁的一个特点是,如果拥有锁的线程的优先级低于请求锁的任务,则优先级较低的任务将提升为更高优先级的任务,以防止优先级倒置其中,中等优先级任务可能会抢占低优先级任务,而锁会增加较高优先级任务必须等待的时间长度,这会导致调度不确定。

以上描述为典型;具体的 RTOS 实现可能不同。例如,FreeRTOS 区分 mutexrecursive mutex,后者支持嵌套特性;而第一个在不需要嵌套的情况下效率稍高。

信号量不仅仅是标志或计数。它们支持发送和等待操作。 user-space 线程可以在信号量上等待而无需进行不必要和不需要的轮询,并在另一个线程或适当设计的 driver/ISR 发送一个单元时 ready/running 'immediately' .

'appropriately-designed driver/ISR',我的意思是可以执行 send() 操作,然后在需要设置等待线程时通过 OS 调度程序退出 ready/running。

这种机制对于抢占式内核至关重要,因为它可以让它们获得非常好的 I/O 性能,而不会在轮询时浪费时间、CPU 周期和内存带宽。非抢占式系统在 I/O 时非常缓慢、延迟缠身且浪费,这就是为什么它们基本上不再使用以及为什么我们忍受所有 synchro/locking/queueing 等问题。