【RTOS面试题】ISR中可以使用互斥锁和信号量吗?

举报
小超嵌入式 发表于 2024/09/05 23:31:45 2024/09/05
【摘要】 在中断服务程序(ISR, Interrupt Service Routine)中直接使用互斥锁(mutex)和信号量(semaphore)是有风险的,因为这些同步机制通常不是中断安全的。但是,可以通过一些方法来安全地在 ISR 中使用互斥锁和信号量。

在中断服务程序(ISR, Interrupt Service Routine)中直接使用互斥锁(mutex)和信号量(semaphore)是有风险的,因为这些同步机制通常不是中断安全的。但是,可以通过一些方法来安全地在 ISR 中使用互斥锁和信号量。在这里插入图片描述

1. 中断安全的互斥锁和信号量

在某些RTOS(实时操作系统)中,提供了中断安全的互斥锁和信号量的实现。这些实现通常在内部做了特殊的处理,使其可以在 ISR 中安全地使用。例如,在 FreeRTOS 中,可以使用互斥锁和信号量的中断安全版本。

2. 通过任务队列传递信号

一种常用的方法是不在 ISR 中直接使用互斥锁或信号量,而是将请求封装成消息,并通过任务队列(task queue)传递给任务(task)。任务在安全的上下文中处理这些消息,从而间接地使用互斥锁或信号量。

3. 禁用中断

在 ISR 中短暂禁用中断可以确保互斥锁和信号量操作的原子性。但是这种方法需要非常小心,因为长时间禁用中断会导致中断丢失或系统响应变慢。

4、示例代码

下面是一个简单的示例,展示了如何在 ISR 中使用互斥锁和信号量:

示例 1: 使用任务队列传递信号

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

// 定义一个任务队列
QueueHandle_t xQueue;

// 定义一个信号量
SemaphoreHandle_t xSemaphore;

void vISRHandler(void *pvParameters)
{
    // 在 ISR 中发送消息给任务队列
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(xQueue, &xHigherPriorityTaskWoken, &xHigherPriorityTaskWoken);
}

void vTaskFunction(void *pvParameters)
{
    for(;;)
    {
        // 从任务队列中接收消息
        if (xQueueReceive(xQueue, NULL, portMAX_DELAY))
        {
            // 在任务中安全地使用互斥锁
            xSemaphoreTake(xSemaphore, portMAX_DELAY);
            // 执行关键操作
            // ...
            xSemaphoreGive(xSemaphore);
        }
    }
}

void main()
{
    xQueue = xQueueCreate(10, sizeof(BaseType_t));
    xSemaphore = xSemaphoreCreateMutex();

    // 创建任务
    xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // 初始化 ISR
    // ...

    // 开始调度
    vTaskStartScheduler();
}

示例 2: 使用中断安全的信号量

#include "FreeRTOS.h"
#include "semphr.h"

SemaphoreHandle_t xSemaphore;

void vISRHandler(void *pvParameters)
{
    // 在 ISR 中使用中断安全的信号量
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken)
    {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

void vTaskFunction(void *pvParameters)
{
    for(;;)
    {
        // 在任务中等待信号量
        xSemaphoreTake(xSemaphore, portMAX_DELAY);
        // 执行关键操作
        // ...
    }
}
void main()
{
    xSemaphore = xSemaphoreCreateBinary();

    // 创建任务
    xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // 初始化 ISR
    // ...

    // 开始调度
    vTaskStartScheduler();
}

5、注意事项

  • 中断禁用:在 ISR 中禁用中断的时间要尽可能短,以避免影响系统的实时性。
  • 中断安全:确保使用的互斥锁和信号量是中断安全的。
  • 任务队列:使用任务队列传递信号是一种常用且安全的方法。

6、扩展:ISR是什么

ISR 是 Interrupt Service Routine(中断服务程序)的缩写。在嵌入式系统和实时操作系统中,ISR 是一种特殊的函数,用于响应外部事件或内部事件的发生。当系统检测到某个事件(称为中断)时,它会暂停当前正在执行的程序,转而去执行 ISR 中定义的代码,以处理中断事件。

7、扩展:ISR 的特点

  1. 快速响应:
    • ISR 需要在尽可能短的时间内完成,以便系统能够尽快恢复到被中断的任务。
  2. 高优先级:
    • ISR 通常具有较高的优先级,这意味着它们可以打断正在运行的任务来处理紧急事件。
  3. 简短且高效:
    • ISR 应该尽可能地简短且高效,以避免长时间占用 CPU 时间片,影响其他任务的执行。
  4. 原子性:
    • ISR 通常被视为原子操作,这意味着在 ISR 执行期间,其他中断会被屏蔽,以防止中断嵌套。
  5. 不可重入:
    • 一般情况下,ISR 不应该被重新进入,即不应该在 ISR 中调用另一个 ISR。

8、扩展: ISR 的应用场景

  1. 硬件中断:
    • 外部设备(如定时器、串口、ADC 等)产生的中断,用于处理输入输出操作。
  2. 软件中断:
    • 由软件触发的中断,用于实现特定的功能,如调度任务等。
  3. 异常处理:
    • 处理硬件故障或软件错误,如除零错误、地址越界等。

9、扩展:ISR 的执行流程

  1. 中断请求:
    • 当某个事件发生时,硬件会向处理器发送中断请求。
  2. 中断处理:
    • 处理器接收到中断请求后,保存当前任务的状态(上下文切换),并跳转到 ISR 的入口地址。
  3. 执行 ISR:
    • ISR 中的代码执行特定的任务,例如读取传感器数据、更新 LED 状态等。
  4. 中断返回:
    • ISR 执行完成后,恢复被中断任务的状态,并返回到中断前的位置继续执行。

10、扩展:ISR 的注意事项

  1. 避免阻塞:
    • ISR 不应该包含阻塞性的操作,如延时或等待,因为这会导致系统响应变慢。
  2. 资源管理:
    • ISR 中应尽量避免使用共享资源,以减少与其他 ISR 或任务之间的冲突。
  3. 中断屏蔽:
    • 在 ISR 中可能会暂时关闭中断,以防止中断嵌套,但在 ISR 结束前必须重新启用中断。
  4. 任务调度:
    • ISR 通常不应直接改变任务的执行顺序,而是通过设置标志等方式通知任务,由任务调度器来决定后续的行为。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。