FreeRTOS实时操作系统的任务通知方法

 更新时间:2022年6月1日 11:20  点击:380 作者:zhzht19861011

前言

注:本文介绍任务通知的基础知识,详细源码分析见FreeRTOS进阶《FreeRTOS高级篇8---FreeRTOS任务通知分析》

每个RTOS任务都有一个32位的通知值,任务创建时,这个值被初始化为0。RTOS任务通知相当于直接向任务发送一个事件,接收到通知的任务可以解除阻塞状态,前提是这个阻塞事件是因等待通知而引起的。发送通知的同时,也可以可选的改变接收任务的通知值。

可以通过下列方法向接收任务更新通知:

  • 不覆盖接收任务的通知值
  • 覆盖接收任务的通知值
  • 设置接收任务通知值的某些位
  • 增加接收任务的通知值

相对于用前必须分别创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。更好的是,相比于使用信号量解除任务阻塞,使用任务通知可以快45%、使用更少的RAM(使用GCC编译器,-o2优化级别)。

使用API函数xTaskNotify()和xTaskNotifyGive()(中断保护等价函数为xTaskNotifyFromISR()和vTaskNotifyGiveFromISR())发送通知,在接收RTOS任务调用API函数xTaskNotifyWait()或ulTaskNotifyTake()之前,这个通知都被保持着。如果接收RTOS任务已经因为等待通知而进入阻塞状态,则接收到通知后任务解除阻塞并清除通知。

RTOS任务通知功能默认是使能的,可以通过在文件FreeRTOSConfig.h中设置宏configUSE_TASK_NOTIFICATIONS为0来禁止这个功能,禁止后每个任务节省8字节内存。

虽然RTOS任务通知速度更快并且占用内存更少,但它也有一些限制:

只能有一个任务接收通知事件。

接收通知的任务可以因为等待通知而进入阻塞状态,但是发送通知的任务即便不能立即完成通知发送也不能进入阻塞状态。

1.发送通知-方法1

1.1函数描述

         BaseType_t xTaskNotify( TaskHandle_txTaskToNotify,
                         uint32_t ulValue,
                         eNotifyAction eAction);

向指定任务发送指定的通知值。如果打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数xTaskNotifyGive()来代替本函数。

此函数不可以在中断服务例程中调用,中断保护等价函数为xTaskNotifyFromISR()。

1.2参数描述

xTaskToNotify:被通知的任务句柄。

ulValue:通知更新值eAction:枚举类型,指明更新通知值的方法

枚举变量成员以及作用如下表所示。

1.3返回值

参数eAction为eSetValueWithoutOverwrite时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

2.发送通知-方法2

2.1函数描述

BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );

其实这是一个宏,本质上相当于xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )。可以使用该API函数代替二进制或计数信号量,但速度更快。在这种情况下,应该使用API函数ulTaskNotifyTake()来等待通知,而不应该使用API函数xTaskNotifyWait()。

此函数不可以在中断服务例程中调用,中断保护等价函数为vTaskNotifyGiveFromISR()。

2.2参数描述

xTaskToNotify:被通知的任务句柄。

2.3用法举例

staticvoid prvTask1( void *pvParameters );
staticvoid prvTask2( void *pvParameters );
/* 保存任务句柄 */
staticTaskHandle_t xTask1 = NULL, xTask2 = NULL;
/* 创建两个任务,它们之间反复发送通知,启动RTOS调度器*/
voidmain( void )
{
    xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 );
    xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 );
    vTaskStartScheduler();
}
/*-----------------------------------------------------------*/
staticvoid prvTask1( void *pvParameters )
{
    for( ;; )
    {
        /*向prvTask2(),发送通知,使其解除阻塞状态 */
        xTaskNotifyGive( xTask2 );
 
        /* 等待prvTask2()的通知,进入阻塞 */
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
    }
}
/*-----------------------------------------------------------*/
staticvoid prvTask2( void *pvParameters )
{
    for( ;; )
    {
        /* 等待prvTask1()的通知,进入阻塞 */
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
        /*向prvTask1(),发送通知,使其解除阻塞状态 */
        xTaskNotifyGive( xTask1 );
    }
}

3.获取通知

3.1函数描述

         uint32_t ulTaskNotifyTake( BaseType_txClearCountOnExit,
                            TickType_txTicksToWait );

ulTaskNotifyTake()是专门为使用更轻量级更快的方法来代替二进制或计数信号量而量身打造的。FreeRTOS获取信号量的API函数为xSemaphoreTake(),可以使用ulTaskNotifyTake()函数等价代替。

当一个任务使用通知值来实现二进制或计数信号量时,其它任务或者中断要使用API函数xTaskNotifyGive()或者使用参数eAction为eIncrement的API函数xTaskNotify()。推荐使用xTaskNotifyGive()函数(其实是个宏,我们这里把它看作一个API函数)。另外需要注意的是,如果在中断中使用,要使用它们的中断保护等价函数:vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。

API函数xTaskNotifyTake()有两种方法处理任务的通知值,一种方法是在函数退出时将通知值清零,这种方法适用于实现二进制信号量;另外一种方法是在函数退出时将通知值减1,这种方法适用于实现计数信号量。

如果RTOS任务的通知值为0,使用xTaskNotifyTake()可以可选的使任务进入阻塞状态,直到该任务的通知值不为0。进入阻塞的任务不消耗CPU时间。

3.2参数描述

xClearCountOnExit:如果该参数设置为pdFALSE,则API函数xTaskNotifyTake()退出前,将任务的通知值减1;如果该参数设置为pdTRUE,则API函数xTaskNotifyTake()退出前,将任务通知值清零。

xTicksToWait:因等待通知而进入阻塞状态的最大时间。时间单位为系统节拍周期。宏pdMS_TO_TICKS用于将指定的毫秒时间转化为相应的系统节拍数。

3.3返回值

返回任务的当前通知值,为0或者为调用API函数xTaskNotifyTake()之前的通知值减1。

3.4用法举例

/* 中断处理程序。*/
voidvANInterruptHandler( void )
{
BaseType_txHigherPriorityTaskWoken;
    prvClearInterruptSource();
     /* xHigherPriorityTaskWoken必须被初始化为pdFALSE。如果调用vTaskNotifyGiveFromISR()会解除vHandlingTask任务的阻塞状态,并且vHandlingTask任务的优先级高于当前处于运行状态的任务,则xHigherPriorityTaskWoken将会自动被设置为pdTRUE。*/
    xHigherPriorityTaskWoken = pdFALSE;
    /*向一个任务发送通知,xHandlingTask是该任务的句柄。*/
    vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken );
    /* 如果xHigherPriorityTaskWoken为pdTRUE,则强制上下文切换。这个宏的实现取决于移植层,可能会调用portEND_SWITCHING_ISR */
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken );
}
/*---------------------------------------------------------------------------------------------------*/
/* 一个因为等待通知而阻塞的任务。*/
voidvHandlingTask( void *pvParameters )
{
BaseType_txEvent;
    for( ;; )
    {
        /*等待通知,无限期阻塞。参数pdTRUE表示函数退出前会清零通知值。这显然是用于替代二进制信号量的用法。需要注意的是,真实的程序一般不会无限期阻塞。*/
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);
        /* 当处理完所有事件后,仍然等待下一个通知*/
        do
        {
            xEvent = xQueryPeripheral();
            if( xEvent != NO_MORE_EVENTS )
            {
                vProcessPeripheralEvent( xEvent);
            }
        } while( xEvent != NO_MORE_EVENTS );
    }
}

4.等待通知

4.1函数描述

         BaseType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry,
                             uint32_tulBitsToClearOnExit,
                             uint32_t*pulNotificationValue,
                             TickType_txTicksToWait );

如果打算使用RTOS任务通知实现轻量级的二进制或计数信号量,推荐使用API函数ulTaskNotifyTake()来代替本函数。

4.2参数描述

ulBitsToClearOnEntry:在使用通知之前,先将任务的通知值与参数ulBitsToClearOnEntry的按位取反值按位与操作。设置参数ulBitsToClearOnEntry为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。

ulBitsToClearOnExit:在函数xTaskNotifyWait()退出前,将任务的通知值与参数ulBitsToClearOnExit的按位取反值按位与操作。

设置参数ulBitsToClearOnExit为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。

pulNotificationValue:用于向外回传任务的通知值。这个通知值在参数ulBitsToClearOnExit起作用前将通知值拷贝到*pulNotificationValue中。如果不需要返回任务的通知值,这里设置成NULL。

xTicksToWait:因等待通知而进入阻塞状态的最大时间。时间单位为系统节拍周期。宏pdMS_TO_TICKS用于将指定的毫秒时间转化为相应的系统节拍数。

4.3返回值

如果接收到通知,返回pdTRUE,如果API函数xTaskNotifyWait()等待超时,返回pdFALSE。

4.4用法举例

/*这个任务使用任务通知值的位来传递不同的事件,这在某些情况下可以代替事件组。*/
voidvAnEventProcessingTask( void *pvParameters )
{
uint32_tulNotifiedValue;
    for( ;; )
    {
        /*等待通知,无限期阻塞(没有超时,所以不用检查函数返回值)。其它任务或者中断设置的通知值中的不同位表示不同的事件。参数0x00表示使用通知前不清除任务的通知值位,参数ULONG_MAX 表示函数xTaskNotifyWait()退出前将任务通知值设置为0*/
        xTaskNotifyWait( 0x00, ULONG_MAX,&ulNotifiedValue, portMAX_DELAY );
 
        /*根据通知值处理事件*/
        if( ( ulNotifiedValue & 0x01 ) != 0)
        {
            prvProcessBit0Event();
        }
        if( ( ulNotifiedValue & 0x02 ) != 0)
        {
            prvProcessBit1Event();
        }
        if( ( ulNotifiedValue & 0x04 ) != 0)
        {
            prvProcessBit2Event();
        }
        /* ……*/
    }
}

5.任务通知并查询

5.1函数描述

         BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
                                 uint32_tulValue,
                                 eNotifyActioneAction,
                                 uint32_t*pulPreviousNotifyValue );

此函数与任务通知API函数xTaskNotify()非常像,只不过此函数具有一个附加参数,用来回传任务当前的通知值,然后根据参数ulValue和eAction更新任务的通知值。

此函数不能在中断服务例程中使用,在中断服务例程中使用xTaskNotifyAndQueryFromISR()函数。

5.2参数描述

xTaskToNotify:被通知的任务句柄。

ulValue:通知更新值

eAction:枚举类型,指明更新通知值的方法,枚举变量成员以及作用见xTaskNotify()一节。

pulPreviousNotifyValue:回传未被更新的任务通知值。如果不需要回传未被更新的任务通知值,这里设置为NULL,这样就等价于调用xTaskNotify()函数。

5.3返回值

参数eAction为eSetValueWithoutOverwrite时,如果被通知任务还没取走上一个通知,又接收到了一个通知,则这次通知值未能更新并返回pdFALSE,否则返回pdPASS。

以上就是FreeRTOS实时操作系统的任务通知方法的详细内容,更多关于FreeRTOS任务通知方法的资料请关注猪先飞其它相关文章!

原文出处:https://freertos.blog.csdn.net/article/details/50578159

[!--infotagslink--]

相关文章

  • php5.3下使用php管理crontab计划任务

    php5.3或以上版本可以使用php管理crontab计划任务,下面我先来体验一下,有需要学习了解的朋友可进入参考。 1.使用php-crontab-manager管理计划任务 要求 PHP>=5.3...2016-11-25
  • tomcat启动完成执行 某个方法 定时任务(Spring)操作

    这篇文章主要介绍了tomcat启动完成执行 某个方法 定时任务(Spring)操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • C#如何对多线程、多任务管理(demo)

    这篇文章主要通过一个小demo介绍了C#如何对多线程、多任务管理,需要的朋友可以参考下...2020-06-25
  • Redis开启键空间通知实现超时通知的步骤详解

    这篇文章主要介绍了Redis开启键空间通知实现超时通知的步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-15
  • c#并行任务多种优化方案分享(异步委托)

    c#并行任务多种优化方案分享,使用异步委托+回调函数方式实现,大家参考使用吧...2020-06-25
  • springboot定时任务@Scheduled执行多次的问题

    这篇文章主要介绍了springboot定时任务@Scheduled执行多次问题的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-18
  • 聊聊通过celery_one避免Celery定时任务重复执行的问题

    Celery Once 也是利用 Redis 加锁来实现, Celery Once 在 Task 类基础上实现了 QueueOnce 类,该类提供了任务去重的功能,今天通过本文给大家介绍通过celery_one避免Celery定时任务重复执行的问题,感兴趣的朋友一起看看吧...2021-10-31
  • Golang Cron 定时任务的实现示例

    这篇文章主要介绍了Golang Cron 定时任务的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-11
  • php定时计划任务与fsockopen持续进程实例

    Web服务器执行一个PHP脚本,有时耗时很长才能返回执行结果,后面的脚本需要等待很长一段时间才能继续执行。如果想实现只简单触发耗时脚本的执行而不等待执行结果就直接执行下一步操作,可以通过fscokopen函数来实现。PHP支...2014-05-31
  • Java并行执行任务的几种方案小结

    这篇文章主要介绍了Java并行执行任务的几种方案小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-11-05
  • Python定义一个Actor任务

    这篇文章主要介绍了Python定义一个Actor任务,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-29
  • PowerShell 远程执行任务的方法步骤

    这篇文章主要介绍了PowerShell 远程执行任务的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-30
  • Element Notification通知的实现示例

    这篇文章主要介绍了Element Notification通知的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-27
  • 详解PHP执行定时任务的实现思路

    这篇文章主要介绍了详解PHP执行定时任务的几种实现思路,PHP的定时任务功能必须通过和其他工具结合才能实现,们就来深入的解析几种常见的php定时任务的思路...2015-12-24
  • win2008中设置计划任务执行PHP文件的方法

    这篇文章主要介绍了win2008中设置计划任务执行PHP文件的方法,需要的朋友可以参考下...2016-07-04
  • Java spring定时任务详解

    这篇文章主要为大家详细介绍了Spring定时任务,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助...2021-10-04
  • spring schedule配置多任务动态cron(增删启停)

    这篇文章主要介绍了spring schedule配置多任务动态cron(增删启停),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-16
  • 如何在thinkphp中使用windows计划任务定时执行php文件

    这篇文章主要介绍了如何在thinkphp中使用windows计划任务定时执行php文件,对定时执行感兴趣的同学,可以参考下...2021-04-21
  • 调试WordPress中定时任务的相关PHP脚本示例

    这篇文章主要介绍了调试WordPress中定时任务的相关PHP脚本示例,针对使用Cron API及wp_schedule_event()函数来写的定时任务,需要的朋友可以参考下...2015-12-14
  • PHP程序自动运行,windows计划任务

    在windows中如果你想让PHP程序自动运行那么我们必须使用windows计划任务来完成了,下面我来给各位同学介绍实现方法。 具体来说,我们若需利用任务计划程序自动运行则...2016-11-25