线程和 ISR 之间的信号量行为

Semaphore behaviour between the thread and an ISR

提问人:chaya kumar 提问时间:11/2/2023 更新时间:11/9/2023 访问量:60

问:

这个问题一直萦绕在我的脑海中,因为我是 RTOS 概念的新手。

假设任务/线程和 ISR 正在使用信号量资源。现在,中断触发器和 ISR 尝试 获取信号量资源,但被另一个任务使用。它是否会导致 ISR 的阻塞条件?通常,我们不应该阻止 ISR。OS/RTOS 如何处理这种情况? 是否有任何灌输 FreeRTOS 或 Linux 内核的解决方案/API?

Linux 内核 嵌入式 FreeRTOS 实时操作系统 Zephyr-RTOS

评论

0赞 OznOg 11/3/2023
等待信号量(显然)会导致睡眠,但在中断上下文中睡眠是被禁止的(会崩溃)。
0赞 chaya kumar 11/3/2023
@OznOg感谢您的回复。是的,我知道在中断上下文中睡觉会崩溃。让我们假设一个场景,ISR 确实需要该资源来完成其工作,但它不可用,您会谁来解决这个问题?
0赞 Clifford 11/3/2023
在这种情况下,ISR 必须向等待资源的任务发出信号。ISR 不能依赖于共享资源。如果你认为你需要这样做,那么你的设计是有缺陷的。
0赞 sawdust 11/20/2023
"OS/RTOS 如何处理这种情况?-- 最简单的解决方案不是使 ISR 复杂化,而是在任务/线程处于关键区域时通过禁用中断来延迟 ISR 的执行。

答:

3赞 Clifford 11/3/2023 #1

不应在中断上下文中使用阻止调用。大多数 RTOS 会发出错误(至少在调试版本中)并停止或以其他方式阻止您这样做。

当然,问题是ISR已经完成。如果你阻止等待一个信号量,那么什么都不会跑来实际给出它。您只能采用之前给出的信号量。

如果您确实在 ISR 中获取信号量,则必须使用非阻塞语义,即立即返回并指示信号量是否可用。根据特定的 RTOS,这可能是 sem take 的特殊版本,或者只是需要零超时参数。然而,在大多数情况下,信号量的这种使用与原子类型的简单共享变量相比没有优势。

也就是说,中断是异步的,信号量是同步原语。很难看出在 ISR 中采用信号量有意义的情况。如果你发现自己这样做,我会质疑你的设计。更可能的用法是 ISR 提供(或递增)信号量以发出等待任务的信号。

这并不难避免 - ISR 除了向线程上下文发出信号(使用信号量或事件标志)外什么都不做,然后线程上下文可以等待信号量与其他线程上下文或其他 ISR 同步(如有必要)。也就是说,如果处理中断事件需要等待其他上下文,则应将处理推迟到允许阻塞的线程上下文。例如,请参阅 FreeRTOS 中的延迟中断处理。

RTOS 在处理可以从 IST 调用哪些 API 的方式上有所不同。有些只是要求非阻塞(零超时)使用标准 API,而其他 API 则具有特定于 ISR 的版本。例如,FreeRTOS 具有 xSemaphoreTakeFromISR(),它不会阻塞。但是,我不会将这种函数的存在视为使用它有任何意义的迹象!很多 FreeRTOS 都是这样的;-)

评论

0赞 chaya kumar 11/8/2023
感谢您的回复。不过,它消除了我的疑虑:)
0赞 Clifford 11/8/2023
@chayakumar 不客气,但是,请看一下当有人回答我的问题时我该怎么办?。特别是最后一段。
0赞 Sparky 11/9/2023 #2

它是否会导致 ISR 的阻塞条件?

简短的回答--不。答案很长——这很复杂。

以下是通常发生的情况。如果确实需要从 ISR 获取信号量,则应为调用方指定零/无等待超时。在这种情况下,当信号量不可用时,它将立即失败并返回。如果指定了非零超时,并且信号量不可用,则它应该立即失败。

然后有一种情况是,如果指定了非零超时的 ISR,但信号量可用,这应该有效吗?这将取决于操作系统。但是,在我看来,最好是导致错误,因为系统不应该在 ISR 中使用非零超时进行奖励。

但是,如果系统实际上试图阻止 ISR 内部,会发生什么?我对此感到头晕目眩,因为具体细节因操作系统而异。简短的回答是没什么好事。长答案是“视情况而定”。然而,一种潜在的情况是......

  1. 系统会错误地认为中断的线程是应该阻塞的线程。
  2. 寄存器值和堆栈信息将(错误地)保存到该线程的控制块中。
  3. 该中断的线程将被(错误地)标记为已阻止,并计划一个新线程。
  4. 事情甚至可能在一段时间内看起来进展正常......直到它没有。

为什么不呢?如果硬件需要某种特殊的中断结束指令序列,那永远不会发生,因为上下文切换很糟糕。这可能会导致中断再也无法得到维修。

还有什么?如果存在专用中断堆栈,则该中断堆栈已被先前标识的中断线程劫持。任何后续中断都将进一步损坏该中断线程现在使用的堆栈(和保存的寄存器)。然后,在该线程重新切换上下文后,崩溃可能会显现出来。

同样,这不会带来任何好处。

我们如何阻止 ISR 内部? 忙等待/旋转,直到满足某些条件。只要被测试的条件由其他东西满足,就可以做到这一点。在 SMP 系统上,这可能是自旋锁 - 自旋锁由不同的 CPU 提供。或者,人们可能正在旋转,等待硬件设置一个就绪的位。无论哪种方式,在这种情况下,都不会在旋转的 CPU 上执行上下文切换。