硬汉嵌入式论坛

 找回密码
 立即注册
查看: 670|回复: 9
收起左侧

[FreeRTOS] 挂起任务再恢复任务,为什么会触发事件

[复制链接]

1

主题

21

回帖

24

积分

新手上路

积分
24
发表于 2025-2-5 14:03:23 | 显示全部楼层 |阅读模式
FreeRTOS任务1内在一直等待事件发生,再执行后面的程序。
但如果其它任务内,挂起任务1后,再恢复任务1,为什么会自动触发事件发生,运行后面的程序了,而不是一直等待事件发生。

任务1:
// 一直等待事件发生,再执行后面程序
osEventFlagsWait(myEvent_Handle, EVENT_FLAG1 | EVENT_FLAG2, osFlagsWaitAny, osWaitForever);

//后面程序....


任务2:

按键1,挂起任务。osThreadSuspend(任务1);

按键2,恢复任务。osThreadResume(任务1);


尝试使用osEventFlagsClear(myEvent_Handle, EVENT_FLAG1 | EVENT_FLAG2);   多个地方加了,也不行。 有点迷糊了。


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2025-2-5 16:02:30 | 显示全部楼层
这个是因为挂起函数在开头把这个任务从事件和延迟列表里面清除掉了


    void vTaskSuspend( TaskHandle_t xTaskToSuspend )
    {
        TCB_t * pxTCB;

        traceENTER_vTaskSuspend( xTaskToSuspend );

        taskENTER_CRITICAL();
        {
            /* If null is passed in here then it is the running task that is
             * being suspended. */
            pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

            traceTASK_SUSPEND( pxTCB );

            /* Remove task from the ready/delayed list and place in the
             * suspended list. */
            if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            /* Is the task waiting on an event also? */
            if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
            {
                ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-5 17:47:26 | 显示全部楼层
eric2013 发表于 2025-2-5 16:02
这个是因为挂起函数在开头把这个任务从事件和延迟列表里面清除掉了

坛主,这个应该如何处理呢,刚学习FreeRTOS,不是很懂。望指教。
回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-5 22:55:56 | 显示全部楼层
[C] 纯文本查看 复制代码
这段代码是 vTaskSuspend 函数中的一部分,用于处理任务被挂起时的情况。以下是代码的详细解释:
代码片段
c
复制
/* Is the task waiting on an event also? */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
    ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
    mtCOVERAGE_TEST_MARKER();
}

vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
逐行解析
1. 检查任务是否正在等待事件
c
复制
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
listLIST_ITEM_CONTAINER 是一个宏或函数,用于检查给定的列表项是否在某个列表中。
pxTCB->xEventListItem 是任务的事件列表项,它表示任务是否正在等待某个事件(例如信号量、队列或其他同步对象)。
如果 listLIST_ITEM_CONTAINER 返回的值不为 NULL,说明任务确实在等待某个事件。
2. 从事件列表中移除任务
c
复制
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
如果任务正在等待事件,使用 uxListRemove 从事件列表中移除任务的 xEventListItem。
(void) 是为了消除编译器对返回值未使用的警告。
uxListRemove 是 FreeRTOS 提供的函数,用于将列表项从其所属的列表中移除。
3. 覆盖率测试标记
c
复制
else
{
    mtCOVERAGE_TEST_MARKER();
}
如果任务不在事件列表中,调用 mtCOVERAGE_TEST_MARKER()。
mtCOVERAGE_TEST_MARKER() 是一个宏,用于代码覆盖率测试。它的作用是标记某些代码路径被覆盖,确保测试工具能够正确统计代码覆盖率。
4. 将任务加入挂起列表
c
复制
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
vListInsertEnd 是 FreeRTOS 提供的函数,用于将列表项插入到指定列表的末尾。
&xSuspendedTaskList 是挂起任务列表的句柄。
&( pxTCB->xStateListItem ) 是任务的状态列表项,表示任务当前的状态。
这一步将任务从原来的就绪列表或事件列表中移除,并插入到挂起任务列表中。
总结
这段代码的核心逻辑是:
检查任务是否在等待事件(例如信号量或队列)。
如果任务在等待事件,则从事件列表中移除任务。
将任务插入到挂起任务列表中,使其暂时停止调度。
使用 mtCOVERAGE_TEST_MARKER() 标记代码覆盖率的路径。
通过这些步骤,vTaskSuspend 确保任务在挂起时不会继续参与调度,并且能够正确处理任务在等待事件时的情况。
回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-5 23:17:19 | 显示全部楼层
问了问AI
总结
任务挂起时,如果任务在等待事件,则从事件列表中移除。
任务恢复时,是否重新添加事件取决于任务的后续需求:
如果需要继续等待事件,调用事件操作 API 重新添加任务到事件列表。
如果不需要继续等待事件,无需重新添加。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2025-2-6 05:21:42 | 显示全部楼层
lyg407 发表于 2025-2-5 17:47
坛主,这个应该如何处理呢,刚学习FreeRTOS,不是很懂。望指教。

意思是调用suspend挂起时,如果被挂起的任务在事件链表或者延迟链表里面,将其从对应的链表里面移除,然后才可以加入到挂起链表里面
回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-6 15:01:13 | 显示全部楼层
eric2013 发表于 2025-2-6 05:21
意思是调用suspend挂起时,如果被挂起的任务在事件链表或者延迟链表里面,将其从对应的链表里面移除,然 ...

  

尝试使用osEventFlagsClear(myEvent_Handle, EVENT_FLAG1 | EVENT_FLAG2);   多个地方加了,也不行。

恢复任务同时再初始化事件一遍, MyEvent_Handle = osEventFlagsNew(&myEvent_attributes);   不行

恢复任务同时再等待一次事件 osEventFlagsWait(myEvent_Handle, EVENT_FLAG1 | EVENT_FLAG2, osFlagsWaitAny, 0);  超时改为0 也不行。

目前解决办法:不采用事件方式了。改为队列,或者信号量传递信息,测试了,都不会出现问题。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2025-2-6 15:15:22 | 显示全部楼层
lyg407 发表于 2025-2-6 15:01
尝试使用osEventFlagsClear(myEvent_Handle, EVENT_FLAG1 | EVENT_FLAG2);   多个地方加了,也 ...

使用其他的通信机制也一样的,这个不会因为你换了通信机制就修改的。suspend对这些通信机制的处理都是一样的。

我觉得你这个程序逻辑设计有问题。简单省事些,你可以判断osEventFlagsWait的返回值,正常得到标志了,才执行对应的程序,而不是楼主位这种,函数后面直接跟个程序执行。

1234.png


回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-6 15:30:54 | 显示全部楼层
eric2013 发表于 2025-2-6 15:15
使用其他的通信机制也一样的,这个不会因为你换了通信机制就修改的。suspend对这些通信机制的处理都是一 ...

是的,谢谢坛主分享的资料。

再去学习一下该函数的详细资料。
回复

使用道具 举报

1

主题

21

回帖

24

积分

新手上路

积分
24
 楼主| 发表于 2025-2-6 17:25:59 | 显示全部楼层
eric2013 发表于 2025-2-6 15:15
使用其他的通信机制也一样的,这个不会因为你换了通信机制就修改的。suspend对这些通信机制的处理都是一 ...

   按照您给的提示,问题解决了。

[C] 纯文本查看 复制代码
#define BIT_0	( 1 << 0 )
#define BIT_4	( 1 << 4 )

void aFunction( EventGroupHandle_t xEventGroup )
{
    EventBits_t uxBits;
    const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;

    /* Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
       the event group. Clear the bits before exiting. */
    uxBits = xEventGroupWaitBits(
               xEventGroup,   /* The event group being tested. */
               BIT_0 | BIT_4, /* The bits within the event group to wait for. */
               pdTRUE,        /* BIT_0 & BIT_4 should be cleared before returning. */
               pdFALSE,       /* Don't wait for both bits, either bit will do. */
               xTicksToWait );/* Wait a maximum of 100ms for either bit to be set. */

    if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
    {
        /* xEventGroupWaitBits() returned because both bits were set. */
    }
    else if( ( uxBits & BIT_0 ) != 0 )
    {
        /* xEventGroupWaitBits() returned because just BIT_0 was set. */
    }
    else if( ( uxBits & BIT_4 ) != 0 )
    {
        /* xEventGroupWaitBits() returned because just BIT_4 was set. */
    }
    else
    {
        /* xEventGroupWaitBits() returned because xTicksToWait ticks passed
           without either BIT_0 or BIT_4 becoming set. */
    }
}


也去查了下API手册,

应该是对事件返回的值进行判断。正常是返回对应事件位,后续可以判断这个事件位。

挂起任务后,返回的是osFlagsErrorTimeout   0xFFFFFFFE  错误代码

另注意:如果按照上述代码判断方式,假如用Bit2=1 判断 时  &  错误代码, 也会 !=0  。

判断方法,需另写即可。

再次感谢坛主指教,授人以鱼不如授人以渔。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-26 00:29 , Processed in 0.269028 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表