FreeRTOS【5】线程阻塞

1.开发背景

       基于上一篇指引,已经了解了线程的挂起和恢复,这个篇章主要测试线程阻塞的方法

2.开发需求

        线程串行阻塞和周期阻塞

3.开发环境

        window10 + MDK + STM32F429 + FreeRTOS10.3.1

4.实现步骤

4.1 线程串行阻塞

        其实在上一篇已经使用了线程阻塞,如果高优先级线程一直不阻塞占用 CPU,程序会直接卡死在高优先级线程中,常用的阻塞方式 vTaskDelay,这个在 FreeRTOS 中非常常用,需要配置宏 INCLUDE_vTaskDelay

#define INCLUDE_vTaskDelay                   1

下面实现 vTaskDelay 实现阻塞延时,定期 1000ms 唤醒一次

/* 串行延时任务 */
static void TaskDelay(void *pvParameters)
{
    for ( ; ; )
    {
        vTaskDelay(1000);
        mspDwt_DelayMs(10);
        Log_Debug("%s\r\n", __func__);
    }
}

结果显示

        由于我们设置的时钟节拍是 1ms,而 vTaskDelay 的输入参数就是时钟节拍,FreeRTOS 的参数基本都是以时钟节拍为单位,如果时钟节拍不是 1ms,则需要注意换算。

        由上述图示可以看出,基本都是每 1000ms 输出一次打印,值得注意的是由于我们测试插入了 mspDwt_DelayMs(10); 的耗时测试操作,每次打印的时间间隔大概是 1010ms,明显会有串行时间累计误差。因此,这种阻塞方式只适用不需要周期唤醒的使用场景。

4.2 线程周期阻塞

        基于上一个执行试验,发现了累计误差,所以当我们需要用到周期唤醒线程时,可以基于 vTaskDelay 的基础上记录每次唤醒的时间点再决定下一次使用 vTaskDelay 的延时参数给多少。事实上,FreeRTOS 已经考虑到了这一点,所以有了 vTaskDelayUntil,可以实现周期性唤醒。

        首先还是需要配置宏

#define INCLUDE_vTaskDelayUntil              1

下面是实现代码,先用 xTaskGetTickCount 获取当前系统的时钟计数值,再定期阻塞

/* 周期延时任务 */
static void TaskDelayUntil(void *pvParameters)
{
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = 1000;
    xLastWakeTime = xTaskGetTickCount();
    
    for( ;; )
    {
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
        
        mspDwt_DelayMs(10);
        Log_Debug("%s\r\n", __func__);
    }
}

结果显示:

由图示可以看出,定期 1000ms 输出一个打印,即使加了 mspDwt_DelayMs(10); 耗时操作也没有影响到线程的周期性唤醒。

4.3 线程退出阻塞

        线程处于阻塞状态有没有办法解除阻塞能,FreeRTOS 作为完善的实时操作系统,当然提供了这样的接口,那就是 xTaskAbortDelay。

1)配置宏开关,打开配置

#define INCLUDE_xTaskAbortDelay              1

2)阻塞一个线程,一直阻塞

/* 串行延时任务 */
static void TaskDelay(void *pvParameters)
{
    for ( ; ; )
    {
        vTaskDelay(portMAX_DELAY);
        Log_Debug("%s\r\n", __func__);
    }
}

3)控制线程定期解除阻塞,这里引入了一个接口 eTaskGetState,可以获取指定线程的状态。

/* 串行延时任务 */
static void TaskCtrl(void *pvParameters)
{
    for ( ; ; )
    {
        vTaskDelay(1000);
        if (eTaskGetState(p->taskDelay) == eBlocked)
        {
            Log_Debug("%s 解除 taskDelay 线程阻塞\r\n", __func__);
            xTaskAbortDelay(p->taskDelay);
        }
    }
}

4)执行现象

每间隔 1000ms 控制线程就强制解除串行延时线程一次,测试结果符合预期。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值