[FreeRTOS学习] 任务通知

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

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

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

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

发送通知

  1. Way 1
BaseType_t xTaskNotify( TaskHandle_txTaskToNotify,  
                           uint32_t ulValue,  
                           eNotifyAction eAction);  
//或
xTaskNotifyGive()

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



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

  1. Way2
BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );

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

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

获取通知

uint32_t ulTaskNotifyTake( BaseType_txClearCountOnExit,  
                           TickType_txTicksToWait );  

参数:

  • xClearCountOnExit:如果该参数设置为pdFALSE,则API函数xTaskNotifyTake()退出前,将任务的通知值减1;如果该参数设置为pdTRUE,则API函数xTaskNotifyTake()退出前,将任务通知值清零。
  • xTicksToWait:因等待通知而进入阻塞状态的最大时间。时间单位为系统节拍周期。宏pdMS_TO_TICKS用于将指定的毫秒时间转化为相应的系统节拍数。
  • 返回当前通知值,为0或者为调用API函数xTaskNotifyTake()之前的通知值减1。

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

它们的中断保护等价函数:vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。

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

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

/* 中断处理程序。*/  
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( voidvoid *pvParameters )  
{  
BaseType_txEvent;  
   
    for( ;; )  
    {  
        /*等待通知,无限期阻塞。参数pdTRUE表示函数退出前会清零通知值。这显然是用于替代二进制信号量的用法。需要注意的是,真实的程序一般不会无限期阻塞。*/  
        ulTaskNotifyTake( pdTRUE, portMAX_DELAY);  
   
        /* 当处理完所有事件后,仍然等待下一个通知*/  
        do  
        {  
            xEvent = xQueryPeripheral();  
   
            if( xEvent != NO_MORE_EVENTS )  
            {  
                vProcessPeripheralEvent( xEvent);  
            }  
   
        } while( xEvent != NO_MORE_EVENTS );  
    }  
}  

等待通知

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

参数

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

  • ulBitsToClearOnExit:在函数xTaskNotifyWait()退出前,将任务的通知值与参数ulBitsToClearOnExit的按位取反值按位与操作。设置参数ulBitsToClearOnExit为0xFFFFFFFF(ULONG_MAX),表示清零任务通知值。

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

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

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

/*这个任务使用任务通知值的位来传递不同的事件,这在某些情况下可以代替事件组。*/  
voidvAnEventProcessingTask( voidvoid *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();  
        }  
   
        /* ……*/  
    }  
}  

任务通知并查询

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

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

  • xTaskToNotify:被通知的任务句柄。
  • ulValue:通知更新值
  • eAction:枚举类型,指明更新通知值的方法,枚举变量成员以及作用见xTaskNotify()一节。
  • pulPreviousNotifyValue:回传未被更新的任务通知值。如果不需要回传未被更新的任务通知值,这里设置为NULL,这样就等价于调用xTaskNotify()函数。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 转自: http://www.jianshu.com/p/486b0965c296 http://www.jia...
    demop阅读 3,874评论 1 21
  • 简述 FreeRTOS 从版本 V8.2.0开始提供任务通知这个功能,每个任务都有一个32位的通知值。按照 Fr...
    orientlu阅读 2,391评论 0 0
  • 以前看了个“八百里分麾下炙”,把“炙”写成了“灸”。写了4章分析记忆。 点击进入闯灸炙涎诞四关1-4之1 今天又看...
    小溪终入海阅读 776评论 3 11
  • 寒假的一天,我准备去小姨家做客。小姨是个特别喜欢猫的女人,回忆中她总是怀里抱着猫和大家笑着说话的样子。我却...
    0utman阅读 298评论 2 0