在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

關于RTOS任務間通信和全局變量之間的區別解析

strongerHuang ? 來源:CSDN技術社區 ? 作者:Mculover666 ? 2021-04-19 09:36 ? 次閱讀

1. 知識點回顧

隊列(queue)是一種只能在一端插入元素、在另一端刪除元素的數據結構,遵循先入先出(FIFO)的規則。

環形隊列(ring queue)可以方便的重復利用這段內存空間,同樣遵循先入先出(FIFO)的規則。

優先級隊列(prio queue)不遵循FIFO,而是根據元素的優先級進行出隊,優先級最高的先出隊。

「本文的所有內容都是基于這兩個數據結構」,TencentOS-tiny中環形隊列和優先級隊列的實現和使用示例請閱讀文章:

數據結構 | TencentOS-tiny中隊列、環形隊列、優先級隊列的實現及使用

2. 消息隊列

2.1. 什么是消息隊列

消息隊列,Message Queue,顧名思義包含兩部分:消息+隊列,或者可以理解為消息的隊列。

① 消息是什么?

兩個不同的任務之間傳遞數據時,這個數據就稱之為消息,這個消息可以是一個整型值,浮點值,甚至一個結構體,一個指針……所以,在使用不同的RTOS的消息隊列時,「一定要注意傳遞的是值還是該值的地址」。

傳遞值的缺點是值的長度有大有小,導致整個消息隊列的長度有大有小。

一個指針的長度是固定的4字節,傳遞值的時候,無論值是什么類型,只傳遞該值的地址。

傳遞地址當然也有缺陷,當動態任務task1中定義了一個局部變量,然后把該局部變量的地址傳給了task2,隨即task1因為某種原因被銷毀,內存回收,導致指向該局部變量的指針變為野指針,非常危險,不過不用慌,小問題,在編程的時候注意避免即可。

「在TencentOS-tiny中,消息隊列中傳遞的消息指的是地址,郵箱隊列傳遞的消息是值」。

② 隊列是什么?

消息隊列如果底層使用環形隊列存儲消息,則成為消息隊列,遵循:先送入的消息先被取出。

消息隊列如果底層使用優先級隊列存儲消息,則成為優先級消息隊列,遵循:優先級最高的消息最先被取出。

「在TencentOS-tiny中,這兩種消息隊列都有,下面一一講述。」

③ pend-post機制

無論是什么隊列,都存在兩種情況:當隊列滿了的時候,元素再入隊會發生錯誤;當隊列為空的時候,元素出隊同樣會發生錯誤。

這種問題可以巧妙的在隊列基礎之上用pend-post機制解決,即等待-釋放機制。

當隊列「滿了」的時候,前來入隊的task1可以選擇pend一段時間或者永久等待,「一旦有元素被task2出隊」,調用post釋放一個信號,「喚醒等待中的task1」。

同樣,當隊列「空了」的時候,前來出隊的task1可以選擇pend一段時間或者永久等待,「一旦有元素被task2入隊」,調用post釋放一個信號,「喚醒等待中的task1」。

是不是很巧妙?

接下來上源碼!上Demo!一看便知~

2.2. 消息隊列的實現

TencentOS-tiny中消息隊列的實現在 tos_message_queue.h和tos_message_queue.c中。

typedef struct k_message_queue_st {

knl_obj_t knl_obj;

pend_obj_t pend_obj;

k_ring_q_t ring_q;

} k_msg_q_t;

一個pend_obj對象用來實現pend-post機制,一個ring_q環形隊列用來存儲消息。

是不是和我講述的沒錯?學透了之后,其實一切都沒有那么神秘的~

再來看看從消息隊列中獲取消息的API實現:

__API__ k_err_t tos_msg_q_pend(k_msg_q_t *msg_q, void **msg_ptr, k_tick_t timeout)

{

//省略了部分源碼

TOS_CPU_INT_DISABLE();

if (tos_ring_q_dequeue(&msg_q-》ring_q, msg_ptr, K_NULL) == K_ERR_NONE) {

TOS_CPU_INT_ENABLE();

return K_ERR_NONE;

}

pend_task_block(k_curr_task, &msg_q-》pend_obj, timeout);

TOS_CPU_INT_ENABLE();

knl_sched();

return err;

}

向消息隊列中存放消息的API實現如下:

__STATIC__ k_err_t msg_q_do_post(k_msg_q_t *msg_q, void *msg_ptr, opt_post_t opt)

{

//省略了部分源碼

TOS_CPU_INT_DISABLE();

if (pend_is_nopending(&msg_q-》pend_obj)) {

err = tos_ring_q_enqueue(&msg_q-》ring_q, &msg_ptr, sizeof(void*));

if (err != K_ERR_NONE) {

TOS_CPU_INT_ENABLE();

return err;

}

TOS_CPU_INT_ENABLE();

return K_ERR_NONE;

}

if (opt == OPT_POST_ONE) {

msg_q_task_recv(TOS_LIST_FIRST_ENTRY(&msg_q-》pend_obj.list, k_task_t, pend_list), msg_ptr);

} else { // OPT_POST_ALL

TOS_LIST_FOR_EACH_ENTRY_SAFE(task, tmp, k_task_t, pend_list, &msg_q-》pend_obj.list) {

msg_q_task_recv(task, msg_ptr);

}

}

TOS_CPU_INT_ENABLE();

knl_sched();

return K_ERR_NONE;

}

從源碼中可以看到,如果opt標志為 OPT_POST_ONE,表示喚醒一個,則喚醒該消息隊列等待列表上任務優先級最高的那個;如果opt標志為 OPT_POST_ALL,則全部喚醒。

2.3. 消息隊列的使用示例

#define MESSAGE_MAX 10

uint8_t msg_pool[MESSAGE_MAX * sizeof(void *)];

k_msg_q_t msg_q;

void entry_task_receiver(void *arg)

{

k_err_t err;

void *msg_received;

while (K_TRUE) {

err = tos_msg_q_pend(&msg_q, &msg_received, TOS_TIME_FOREVER);

if (err == K_ERR_NONE) {

printf(“receiver: msg incoming[%s]

”, (char *)msg_received);

}

}

}

void entry_task_sender(void *arg)

{

char *msg_prio_0 = “msg 0 without priority”;

char *msg_prio_1 = “msg 1 without priority”;

char *msg_prio_2 = “msg 2 without priority”;

printf(“sender: post a message 2 without priority

”);

tos_msg_q_post(&msg_q, msg_prio_2);

printf(“sender: post a message 1 without priority

”);

tos_msg_q_post(&msg_q, msg_prio_1);

printf(“sender: post a message 0 without priority

”);

tos_msg_q_post(&msg_q, msg_prio_0);

}

執行結果如下:

TencentOS-tiny Port on STM32L431RCT6 By Mculover666

sender: post a message 2 without priority

sender: post a message 1 without priority

sender: post a message 0 without priority

receiver: msg incoming[msg 2 without priority]

receiver: msg incoming[msg 1 without priority]

receiver: msg incoming[msg 0 without priority]

3. 優先級消息隊列3.1. 優先級消息隊列的實現

實現和消息隊列類似,通過在優先級隊列的基礎上加上pend-post機制來實現。

TencentOS-tiny中優先級消息隊列的實現在tos_priority_message_queue.h和tos_priority_message_queue.c中。

typedef struct k_priority_message_queue_st {

knl_obj_t knl_obj;

pend_obj_t pend_obj;

void *prio_q_mgr_array;

k_prio_q_t prio_q;

} k_prio_msg_q_t;

其中pend_obj用于掛載等待該優先級消息隊列的任務,prio_q和prio_q_mgr_array合起來實現優先級隊列。

消息入隊和消息出隊的API實現與消息隊列的實現思想一模一樣,這里不再講解。

3.2. 優先級消息隊列的使用示例

#define MESSAGE_MAX 10

uint8_t msg_pool[MESSAGE_MAX * sizeof(void *)];

k_prio_msg_q_t prio_msg_q;

void entry_task_receiver(void *arg)

{

k_err_t err;

void *msg_received;

while (K_TRUE) {

err = tos_prio_msg_q_pend(&prio_msg_q, &msg_received, TOS_TIME_FOREVER);

if (err == K_ERR_NONE) {

printf(“receiver: msg incoming[%s]

”, (char *)msg_received);

}

}

}

void entry_task_sender(void *arg)

{

char *msg_prio_0 = “msg with priority 0”;

char *msg_prio_1 = “msg with priority 1”;

char *msg_prio_2 = “msg with priority 2”;

printf(“sender: post a message with priority 2

”);

tos_prio_msg_q_post(&prio_msg_q, msg_prio_2, 2);

printf(“sender: post a message with priority 1

”);

tos_prio_msg_q_post(&prio_msg_q, msg_prio_1, 1);

printf(“sender: post a message with priority 0

”);

tos_prio_msg_q_post(&prio_msg_q, msg_prio_0, 0);

}

運行結果如下:

TencentOS-tiny Port on STM32L431RCT6 By Mculover666

sender: post a message with priority 2

sender: post a message with priority 1

sender: post a message with priority 0

receiver: msg incoming[msg with priority 0]

receiver: msg incoming[msg with priority 1]

receiver: msg incoming[msg with priority 2]

?

將第2節的結果和第3節的結果對比,就會發現同樣的消息發送順序,因為使用不同的消息隊列,任務獲取到的消息順序截然不同。

4. 郵箱隊列

4.1. 不同之處

消息隊列和郵箱隊列的不同之處,在于底層隊列每個元素類型不一樣,看一眼源碼便知。

消息隊列傳遞的消息是地址,所以在初始化消息隊列的時候,環形隊列中每個元素都是空指針類型:

__API__ k_err_t tos_msg_q_create(k_msg_q_t *msg_q, void *pool, size_t msg_cnt)

{

//部分源碼省略

//重點:隊列中每個元素類型大小是sizeof(void*)

err = tos_ring_q_create(&msg_q-》ring_q, pool, msg_cnt, sizeof(void *));

if (err != K_ERR_NONE) {

return err;

}

return K_ERR_NONE;

}

而郵箱隊列傳遞的是值,所以在初始化底層用到的環形隊列時,每個元素的大小是由用戶指定的:

__API__ k_err_t tos_mail_q_create(k_mail_q_t *mail_q, void *pool, size_t mail_cnt, size_t mail_size)

{

//省略了部分源碼

//重點:每個元素的大小是mail_size,由用戶傳入參數指定

err = tos_ring_q_create(&mail_q-》ring_q, pool, mail_cnt, mail_size);

if (err != K_ERR_NONE) {

return err;

}

return K_ERR_NONE;

}

4.2. 郵箱隊列的實現

這有什么好實現的~一個環形隊列+pend-post對象即可。

TencentOS-tiny中郵箱隊列的實現在tos_mail_queue.h和tos_mail_queue.c中。

typedef struct k_mail_queue_st {

knl_obj_t knl_obj;

pend_obj_t pend_obj;

k_ring_q_t ring_q;

} k_mail_q_t;

是不是沒什么區別~至于操作的API,更沒啥區別,不寫了,劃水劃水。

4.3. 郵箱隊列的使用示例

#define MAIL_MAX 10

typedef struct mail_st {

char *message;

int payload;

} mail_t;

uint8_t mail_pool[MAIL_MAX * sizeof(mail_t)];

k_mail_q_t mail_q;

void entry_task_receiver_higher_prio(void *arg)

{

k_err_t err;

mail_t mail;

size_t mail_size;

while (K_TRUE) {

err = tos_mail_q_pend(&mail_q, &mail, &mail_size, TOS_TIME_FOREVER);

if (err == K_ERR_NONE) {

TOS_ASSERT(mail_size == sizeof(mail_t));

printf(“higher: msg incoming[%s], payload[%d]

”, mail.message, mail.payload);

}

}

}

void entry_task_receiver_lower_prio(void *arg)

{

k_err_t err;

mail_t mail;

size_t mail_size;

while (K_TRUE) {

err = tos_mail_q_pend(&mail_q, &mail, &mail_size, TOS_TIME_FOREVER);

if (err == K_ERR_NONE) {

TOS_ASSERT(mail_size == sizeof(mail_t));

printf(“lower: msg incoming[%s], payload[%d]

”, mail.message, mail.payload);

}

}

}

void entry_task_sender(void *arg)

{

int i = 1;

mail_t mail;

while (K_TRUE) {

if (i == 2) {

printf(“sender: send a mail to one receiver, and shoud be the highest priority one

”);

mail.message = “1st time post”;

mail.payload = 1;

tos_mail_q_post(&mail_q, &mail, sizeof(mail_t));

}

if (i == 3) {

printf(“sender: send a message to all recevier

”);

mail.message = “2nd time post”;

mail.payload = 2;

tos_mail_q_post_all(&mail_q, &mail, sizeof(mail_t));

}

if (i == 4) {

printf(“sender: send a message to one receiver, and shoud be the highest priority one

”);

mail.message = “3rd time post”;

mail.payload = 3;

tos_mail_q_post(&mail_q, &mail, sizeof(mail_t));

}

if (i == 5) {

printf(“sender: send a message to all recevier

”);

mail.message = “4th time post”;

mail.payload = 4;

tos_mail_q_post_all(&mail_q, &mail, sizeof(mail_t));

}

tos_task_delay(1000);

++i;

}

}

運行結果為:

TencentOS-tiny Port on STM32L431RCT6 By Mculover666

sender: send a mail to one receiver, and shoud be the highest priority one

higher: msg incoming[1st time post], payload[1]

sender: send a message to all recevier

higher: msg incoming[2nd time post], payload[2]

lower: msg incoming[2nd time post], payload[2]

sender: send a message to one receiver, and shoud be the highest priority one

higher: msg incoming[3rd time post], payload[3]

sender: send a message to all recevier

higher: msg incoming[4th time post], payload[4]

lower: msg incoming[4th time post], payload[4]

此示例主要演示了兩點:1. 如何使用郵箱隊列直接傳遞值;2. 喚醒一個等待任務和喚醒所有等待任務的區別。

5. 優先級郵箱隊列

看到這里,這個不能再講了吧~

TencentOS-tiny中實現在tos_priority_mail_queue.c 和tos_priority_mail_queue.h中。

可以自己嘗試根據前面的demo,編寫出一個使用優先級郵箱隊列的demo,測試高優先級的郵件是否會被先收到,然后將結果與第4節的實驗結果進行對比。

越到文末我越浪,劃水已經不能滿足了,博主要去摸魚~

6. 總結

按照慣例,對本文所講的內容進行一個總結。

本文主要講述了用于任務間通信的一些內核對象,主要有四個:消息隊列和優先級消息隊列,郵箱隊列和優先級郵箱隊列。

接下來列出一些重要的點:

① 「在使用RTOS中的一些用于任務間通信的量時,要注意傳遞的是值還是地址。TencentOS-tiny中消息隊列傳輸的是地址,而郵箱隊列傳遞的是值。」

② 「消息隊列和郵箱隊列基于環形隊列實現,遵循FIFO規則;而優先級消息隊列和優先級郵箱隊列基于優先級隊列實現,遵循按照元素優先級取出的規則。」

最后來回答題目中的問題:任務間通信為什么不使用全局變量?

① 無論是消息隊列還是郵箱隊列,都是利用了全局變量可以被隨意訪問的特性,所以使用時都會被定義為全局變量。

② 普通全局變量可用于一些簡單的任務間通信場合。

③ 相較于普通全局變量,加入隊列機制可以存儲多個消息,加入pend-post機制可以擁有任務等待和喚醒的機制,用于解決隊列已滿或隊列為空的問題。
編輯:lyn

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • fifo
    +關注

    關注

    3

    文章

    390

    瀏覽量

    43922
  • RTOS
    +關注

    關注

    22

    文章

    821

    瀏覽量

    119944
  • 消息隊列
    +關注

    關注

    0

    文章

    33

    瀏覽量

    3020

原文標題:RTOS任務間通信和全局變量有什么區別?

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    使用任務通知提高RTOS應用的效率

    在實時嵌入式系統中,性能和資源效率是決定設計成敗的關鍵因素。傳統的實時操作系統(RTOS)提供了如隊列、信號量和事件組機制,實現任務之間的同步和通信。FreeRTOS/SAFERTOS
    的頭像 發表于 12-27 14:54 ?358次閱讀

    freertos和rtos區別是什么

    FreeRTOS 和 RTOS(實時操作系統)是兩個不同的概念,但它們之間有緊密的聯系。FreeRTOS 是一個特定的開源實時操作系統,而 RTOS 是實時操作系統的一般概念。 概念定義 RT
    的頭像 發表于 09-02 14:18 ?1623次閱讀

    LABVIEW調用DLL,DLL中包含全局變量不識別的問題

    頭文件中寫法如上,.cpp文件中寫法如下 導入DLL時,錯誤如下 這個報錯就很沒有道理 我在同樣的文件中按同樣的寫法,寫一個add(a,b,c)函數,同樣寫全局變量的話,它就不會報這樣的錯,所以我可以排除是頭文件或者預處理定義的問題。 很頭疼,有沒有大神指導一下。
    發表于 05-31 09:37

    建立更多的全局變量的時候,如何使得PROGRAM SIZE不增大呢?

    今天發現,建立更多的全局變量的時候,PROGRAM SIZE同時也增大了,如何使得PROGRAM SIZE不增大呢?我對全局變量的初始化無要求。
    發表于 05-15 06:30

    COSMIC在外部中斷中修改全局變量后,發現在主程序中,修改的值又變回來了,為什么?

    我用的COSMIC,在外部中斷中修改全局變量后,發現在主程序中,修改的值又變回來了(比如說我想計數外部中斷的次數)。這是怎么回事?而我在定時中斷中卻可以修改全局變量
    發表于 05-13 08:45

    使用IAR定義全局變量出現兩個同名不同地址變量是什么原因導致的?

    使用IAR定義全局變量出現兩個同名不同地址變量 systickCount和systickFlag都在另一個c文件里定義的,假設a.c,然后在a.h里聲明為外部變量,main.c
    發表于 05-10 06:09

    請問ucos中全局變量OSTime最終能累加到多少呢?

    在ucos-ii 中全局變量 OSTime 總是++請問最終能累加到多少呢? 若加到65530后 會自動歸零嗎?
    發表于 05-09 06:22

    請問stm32程序中如何優化大量的編譯開關和全局變量

    剛接手一個程序,發現里面存在大量的編譯開關和定義了大量的全局變量,感覺這些顯得很是臃腫,有什么方法可以優化一下這些編譯開關和全局變量全局變量是一個個的標志位,有時候還會有條件嵌套。
    發表于 05-06 06:35

    你是不是也沒躲過這個坑?用了太多全局變量......

    全局變量太多有哪些弊端?該如何規避,以及如何管理全局變量等。一、全局變量太多有哪些弊端?真正做過項目的同學應該都能明白,項目中全局變量太多,會存在很多問題。這里給大家羅列一些太多
    的頭像 發表于 05-01 08:10 ?626次閱讀
    你是不是也沒躲過這個坑?用了太多<b class='flag-5'>全局變量</b>......

    STM8L使用中全局變量自動更改是怎么回事?

    問題是這樣的,我在使用STM8L的時候,定義了一個全局變量A,只在初始化的時候賦了一個初值A=5,在整個程序生命過程中,沒有任何一個地方改變這個初值。目前遇到在程序運行中,讀出的這個A的值為0,請問是否可以確定為內存溢出或者其他什么問題 有遇到類似情況的嗎,求指導
    發表于 04-28 06:03

    全局變量太多有哪些弊端?

    隨著全局變量的增多,不同模塊的變量名可能會產生沖突或混淆,導致代碼難以理解和維護。同時,全局變量使得代碼中的依賴關系變得復雜,難以追蹤和理解。這增加了新開發人員的學習成本,也增加了修改和調試的難度。
    發表于 04-24 09:15 ?967次閱讀

    求助,關于FreeRTOS的相關疑問求解

    1.最近在學習FreeRTOS(stm32下),雖然好像知道了隊列和信號量是用來做任務之間通信的,但是不太理解為什么要用這些東西,我覺得好像用rtos的隊列和信號量要實現的功能,我定
    發表于 04-24 07:08

    請問ModusToolbox下針對CYW20719B2編程,能否指定全局變量地址?

    請問ModusToolbox 下針對CYW20719B2編程,能否指定全局變量地址? 謝謝
    發表于 03-01 11:13

    關于PSDR和DSPR遇到的兩個問題求解

    PSPR 主要用途放置靜態函數,提示高函數數執行效率 DSPR 主要用途于全局變量、場景保護的上下文管理與等數據 以上是我找到的關于 PSPR 和 DSPR 的解析,我有兩個問題: 1。PSPR
    發表于 02-26 07:57

    請問core2里的程序可以直接使用core1里的全局變量嗎?

    如題,core2里的程序可以直接使用core1里的全局變量嗎?就是不同核之前可以直接通信嗎?是否還需要配置一些東西才能實現核通信
    發表于 02-20 08:05
    主站蜘蛛池模板: 色婷婷色综合缴情在线 | 久久久一本 | 亚洲一级免费毛片 | 精品女同同性视频很黄很色 | 香港经典a毛片免费观看爽爽影院 | 理论片免费午夜 | 国产成人mv 在线播放 | 狠狠躁夜夜躁人人爽天天天天 | 国产高清小视频 | 欧美性猛交xxxx乱大交中文 | 在线观看精品视频看看播放 | 狠狠干成人 | www.黄com| 四虎永久免费网站 | 亚洲黄色小视频 | 午夜嘿咻| 婷婷午夜激情 | 午夜老司机福利 | 狠狠色综合网 | 国产午夜免费 | 视频在线一区二区 | 国模视频一区二区 | 亚洲免费资源 | 亚洲韩国欧美一区二区三区 | 免费在线观看一级毛片 | 婷婷丁香在线 | 久久狠狠第一麻豆婷婷天天 | 国产午夜亚洲精品 | jlzzjlzz亚洲日本 | 天天天天做夜夜夜夜 | 自拍偷拍福利 | 午夜在线观看免费高清在线播放 | 日本加勒比官网 | 日本有色视频 | 久久国产乱子伦精品免费午夜 | 日韩1| 久久777国产线看观看精品卜 | 手机福利在线观看 | 手机看片自拍自自拍日韩免费 | 四虎在线免费视频 | 2022年永久免费观看 |