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

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

3天內(nèi)不再提示

rt-thread心法系列(一)那些你必須知道的幾類 api

出出 ? 來源:出出 ? 作者:出出 ? 2022-07-08 08:49 ? 次閱讀

前言

多任務系統(tǒng),線程和中斷是兩個競爭關(guān)系的各自獨立的實體。很多 api 是禁止在中斷中調(diào)用的。
和線程運行息息相關(guān)的函數(shù),要求必須在任務調(diào)度運行起來以后才能使用。
以及,一些 api 被設計出來是用來在某線程操作另外一個線程,是不可以某線程針對自己使用的。
今天就說說哪些 api 禁止在中斷中調(diào)用、哪些必須在任務調(diào)度器運行以后才能使用、哪些不能線程用在自己身上。

禁止在中斷調(diào)用的 api 列表

內(nèi)存堆操作類

rt_system_heap_init
rt_malloc
rt_realloc
rt_free

內(nèi)存池類

rt_mp_create
rt_mp_delete
rt_mp_alloc

內(nèi)核對象類

rt_object_allocate
rt_object_find

idle 線程

rt_defunct_execute

ipc 同步和消息機制類

rt_sem_create
rt_sem_delete
rt_mutex_create
rt_mutex_trytake
rt_mutex_delete
rt_event_create
rt_event_delete
rt_mb_create
rt_mb_delete
rt_mq_create
rt_mq_delete

完成量

rt_completion_wait

隊列類

rt_wqueue_wait
rt_data_queue_push
rt_data_queue_pop

延時

rt_thread_sleep
rt_thread_delay
rt_thread_delay_until
rt_thread_mdelay

注:源碼中摘錄,并無理論考證,更無實際驗證

所有被禁止在中斷中調(diào)用的函數(shù)都有個相似的特征 —— 它可能是阻塞的,導致中斷無法短時間內(nèi)返回;或者它想調(diào)用可能發(fā)生阻塞的 api 。
任何引用了他們的函數(shù)也被帶跑了,不能在中斷中使用。

RT_DEBUG_NOT_IN_INTERRUPT 調(diào)試宏定義

rt-thread 定義了一個宏,當我們開啟調(diào)試的時候,它可以幫我檢查當前函數(shù)是否被中斷調(diào)用了。其實現(xiàn)如下:

#define RT_DEBUG_NOT_IN_INTERRUPT                                             \
do                                                                            \
{                                                                             \
   rt_base_t level;                                                          \
   level = rt_hw_interrupt_disable();                                        \
   if (rt_interrupt_get_nest() != 0)                                         \
   {                                                                         \
       rt_kprintf("Function[%s] shall not be used in ISR\n", __FUNCTION__);  \
       RT_ASSERT(0)                                                          \
   }                                                                         \
   rt_hw_interrupt_enable(level);                                            \
}                                                                             \
while (0)

當你在源碼里看見某個函數(shù)體中有一行

引用 RT_DEBUG_NOT_IN_INTERRUPT 調(diào)試宏的幾點問題

1. rt-thread 中有多處引用了這個宏,上面函數(shù)列表里絕大部分有;
2. 有一些沒有,比如 memheap.c 文件中的 `rt_memheap_alloc` `rt_memheap_realloc` 等操作。
3. 仔細查看引用了 `RT_DEBUG_NOT_IN_INTERRUPT` 的所有函數(shù),有部分使用宏的地方真讓人揪心,以 `rt_defunct_execute` 函數(shù)為例:

   static void rt_defunct_execute(void)
   {
       // Loop until there is no dead thread. 
       // So one call to rt_defunct_execute
       // will do all the cleanups. */
       while (1)
       {
           register rt_base_t level;
           rt_thread_t thread;
           void (*cleanup)(struct rt_thread *tid);
#ifdef RT_USING_MODULE
           struct rt_dlmodule *module = RT_NULL;
#endif
           RT_DEBUG_NOT_IN_INTERRUPT;          // <<--

為什么放 while 里?不是 while 之前?不應該放到函數(shù)開頭醒目的地方嗎?有人反駁了啊,放哪兒不一樣,放哪也是一行代碼的事兒!
RT_DEBUG_IN_THREAD_CONTEXT 也有用樣的使用不當,放到某個判斷內(nèi)部,而不是函數(shù)開頭就引用。
4. 那么我還有個疑問:這是 idle 線程的內(nèi)部調(diào)用的局部函數(shù),會被中斷調(diào)用了?!誰有權(quán)限在中斷里引用它?!**`rt_defunct_execute` 函數(shù)應該從上面的列表里刪除掉**,這個筆者已經(jīng)在 github 上 pr 修改過了

必須在線程上下文調(diào)用的 api 列表

信號

rt_signal_wait

ipc 同步和消息機制

rt_sem_take
rt_mutex_take
rt_mutex_release
rt_event_recv
rt_mb_send_wait
rt_mb_recv
rt_mq_send_wait
rt_mq_recv

線程操作類

rt_thread_detach
rt_thread_delete
rt_thread_yield
rt_thread_delay
rt_thread_delay_until
rt_thread_mdelay
rt_thread_suspend
rt_thread_resume

其它

rt_tick_get
rt_enter_critical
rt_exit_critical

可以這么說,任務調(diào)度器啟動前,只允許 init/create/startup 某線程。
雖然,沒有發(fā)現(xiàn)有誰在任務調(diào)度器啟動前調(diào)用 `rt_thread_suspend` ,但是,有一大批人想使用 `rt_thread_mdelay` 幾個延時函數(shù)。以上這幾個函數(shù)開頭都應該添加 `RT_DEBUG_IN_THREAD_CONTEXT` 檢測,在源碼中用于明示此 api 的使用限制。

RT_DEBUG_IN_THREAD_CONTEXT 調(diào)試宏定義

首先,貼出來它的定義

#define RT_DEBUG_IN_THREAD_CONTEXT                                            \
   RT_DEBUG_NOT_IN_INTERRUPT;                                                \
do                                                                            \
{                                                                             \
   rt_base_t level;                                                          \
   level = rt_hw_interrupt_disable();                                        \
   if (rt_thread_self() == RT_NULL)                                          \
   {                                                                         \
       rt_kprintf("Function[%s] shall not be used before scheduler start\n", \
                  __FUNCTION__);                                             \
       RT_ASSERT(0)                                                          \
   }                                                                         \
   rt_hw_interrupt_enable(level);                                            \
}                                                                             \
while (0)
#else
#define RT_DEBUG_NOT_IN_INTERRUPT
#define RT_DEBUG_IN_THREAD_CONTEXT
#endif

注:此定義代碼略有改動。

在線程上下文調(diào)用的函數(shù)有兩個特征:
1. 不能在中斷中調(diào)用。
2. 不能在任務調(diào)度器啟動前調(diào)用,必須線程啟動后,被線程入口函數(shù)調(diào)用。

因此,函數(shù)體中添加了此宏引用的函數(shù),也不能在中斷響應過程中被調(diào)用。

鑒于此,本篇開頭的***“禁止在中斷調(diào)用的 api 列表” 需要進行擴充,添加上 “必須在線程上下文調(diào)用的 api 列表” 中的所有 api***。

不能用在線程自己身上的 api

首先,這類 api 有個特征,那就是形參有個 rt_thread_t 類型參數(shù)

rt_thread_detach
rt_thread_delete

這倆不多說,一個針對靜態(tài)線程對象,一個針對動態(tài)線程對象。作用均是退出線程、清理線程。當前線程退出可以直接從 while 循環(huán)里跳出來,從線程入口函數(shù) return 就可以。

`rt_thread_startup` 當一個線程正在運行的時候,它自己再 startup 自己是不是就很詭異了。

`rt_thread_resume` 線程掛起由得自己,喚醒就由不得自己了。

`rt_thread_control` 控制某線程的動作可能有:改變優(yōu)先級、啟動線程、關(guān)閉線程、以及多核cpu上綁定線程到某 cpu。某線程偷偷修改自己的運行優(yōu)先級也說得過去;自己想換個 cpu 核心做依靠,看似也可以,但是,知道當前核的感受嗎?有 cpu 資源可用已經(jīng)不錯了,不是嗎?
因此,這個 api 只能用來修改自己的優(yōu)先級。

特別的,目前 rt-thread 只支持當前線程自己主動 suspend ,然后等待中斷或者其它線程 resume 它。而且,僅限于定時、線程間同步和通信機制里使用。不支持 A 線程 suspend B 線程,然后某個時機再 resume B。不支持 `rt_thread_suspend` `rt_thread_resume` 直接調(diào)用。
雖然 `rt_thread_detach` `rt_thread_delete` 用來退出線程,但是,不了解線程運行機制,千萬別隨意使用這倆函數(shù)退出其它線程。如果有需要,使用消息機制讓現(xiàn)在自己跳出線程入口函數(shù)的 while 循環(huán),自己從線程入口函數(shù)返回,這樣更安全可靠。

結(jié)束


感謝您的閱讀,歡迎各位提出意見,對文中的不當之處不吝賜教。

審核編輯:湯梓紅

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

    關(guān)注

    2

    文章

    1461

    瀏覽量

    61490
  • 多任務系統(tǒng)
    +關(guān)注

    關(guān)注

    0

    文章

    11

    瀏覽量

    6866
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1239

    瀏覽量

    39434
收藏 人收藏

    評論

    相關(guān)推薦

    RT-Thread記錄(、版本開發(fā)環(huán)境及配合CubeMX)

    RT-Thread 學習記錄的第篇文章,RT-Thread記錄(、RT-Thread 版本、RT-T
    的頭像 發(fā)表于 06-20 00:28 ?4925次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(<b class='flag-5'>一</b>、版本開發(fā)環(huán)境及配合CubeMX)

    RT-Thread記錄(二、RT-Thread內(nèi)核啟動流程)

    在前面我們RT-Thread Studio工程基礎(chǔ)之上講RT-Thread內(nèi)核啟動流程.
    的頭像 發(fā)表于 06-20 00:30 ?4784次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(二、<b class='flag-5'>RT-Thread</b>內(nèi)核啟動流程)

    【原創(chuàng)精選】RT-Thread征文精選技術(shù)文章合集

    rt-thread心法系列那些必須知道幾類
    發(fā)表于 07-26 14:56

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實時操作系統(tǒng),本文是RT-Thread實時操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread AI kit開源:輕松實現(xiàn)鍵部署AI模型至 RT-Thread

    RT-AK 是 RT-Thread 團隊為 RT-Thread 實時操作系統(tǒng)所開發(fā)的 AI 套件,能夠鍵將 AI 模型部署到 RT-Thread
    發(fā)表于 01-25 18:18 ?3次下載
    <b class='flag-5'>RT-Thread</b> AI kit開源:輕松實現(xiàn)<b class='flag-5'>一</b>鍵部署AI模型至 <b class='flag-5'>RT-Thread</b>

    RT-Thread新版入門系列教程18講

    作為名 RTOS 的初學者,也許RT-Thread 還比較陌生。然而,隨著的深入接觸,會逐漸發(fā)現(xiàn)
    發(fā)表于 01-25 20:00 ?0次下載
    <b class='flag-5'>RT-Thread</b>新版入門<b class='flag-5'>系列</b>教程18講

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例

    RT-Thread全球技術(shù)大會:RT-Thread測試用例集合案例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:34 ?1962次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:<b class='flag-5'>RT-Thread</b>測試用例集合案例

    rt-thread 心法系列(二) 使用寶典

    接觸 rt-thread 已有半年,混論壇也5個半月了,期間遇到過各種奇奇怪怪的棘手問題,有過尷尬,也自信曾經(jīng)提供過比較妙的應對方案。所以產(chǎn)生了將些典型的使用技巧匯總分享出來的想法,遂有此篇。
    的頭像 發(fā)表于 07-08 09:41 ?2946次閱讀
    <b class='flag-5'>rt-thread</b> <b class='flag-5'>心法系列</b>(二) 使用寶典

    RT-Thread學習筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡介 作為名 RTOS 的初學者,也許RT-Thread 還比較陌生。然而,隨著的深入接觸,
    的頭像 發(fā)表于 07-09 11:27 ?4321次閱讀
    <b class='flag-5'>RT-Thread</b>學習筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
    發(fā)表于 02-22 18:23 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    基于RT-Thread Studio學習

    前期準備:從官網(wǎng)下載 RT-Thread Studio,弄個賬號登陸,開啟rt-thread學習之旅。
    的頭像 發(fā)表于 05-15 11:00 ?3497次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio學習

    基于 RT-Thread 的 RoboMaster 電控框架(

    。但也正是因為這些優(yōu)點的覆蓋面較廣,很多初學者會覺得無從下手,但只要步入 RT-Thread 的大門,就發(fā)現(xiàn)她的美好。這系列文檔將作為本人基于 RT-Thread 開發(fā) RoboMa
    的頭像 發(fā)表于 09-19 19:55 ?641次閱讀

    RT-Thread v5.0.2 發(fā)布

    一系列令人激動的變化和改進。 以下是些亮點和關(guān)鍵變更: ?內(nèi)核改進: ●?新增了AMP支持。 ●?新增了消息隊列的消息優(yōu)先級。 ●?新增了rt_hw_interrupt_is_disabled
    的頭像 發(fā)表于 10-10 18:45 ?1202次閱讀
    <b class='flag-5'>RT-Thread</b> v5.0.2 發(fā)布