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

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

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

rt-thread 優(yōu)化系列(四)信號(hào)對(duì) ipc 的影響

出出 ? 來源:出出 ? 作者:出出 ? 2022-06-23 09:51 ? 次閱讀

前言

信號(hào) signal,并不是線程間同步的信號(hào)量 semaphore。后者是線程間同步機(jī)制的一種,而前者是線程間異步通信的一種。
官方文檔里對(duì)其解釋是:“信號(hào)(又稱為軟中斷信號(hào)),在軟件層次上是對(duì)中斷機(jī)制的一種模擬,在原理上,一個(gè)線程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求可以說是類似的?!?/p>

信號(hào)本質(zhì)是**軟中斷**,用來通知線程發(fā)生了異步事件,**用做線程之間的異常通知、應(yīng)急處理**。一個(gè)**線程不必通過任何操作來等待信號(hào)的到達(dá)**,事實(shí)上,**線程也不知道信號(hào)到底什么時(shí)候到達(dá)**。線程之間可以互相通過調(diào)用 `rt_thread_kill` 發(fā)送信號(hào)。

以上畫線部分是我特意要大家注意的,我們要看待中斷回調(diào)函數(shù)那樣,看待信號(hào)回調(diào)函數(shù)**被執(zhí)行的實(shí)機(jī)**,但不需要過分擔(dān)憂的是回調(diào)函數(shù)**執(zhí)行時(shí)間**,因?yàn)?*終究信號(hào)回調(diào)函數(shù)還是在線程上下文被執(zhí)行的**。

從官方文檔可以清楚了解到,使用信號(hào)很簡(jiǎn)單,安裝信號(hào)、解除信號(hào)掩碼、發(fā)送信號(hào)、處理信號(hào)等幾個(gè)過程。

更多關(guān)于信號(hào)的原理詳見官方文檔 [信號(hào)]( https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e4%bf%a1%e5%8f%b7 )

一個(gè)示例引起的血案

官方原版示例筆者就不貼出來了,直接拷貝到自己的項(xiàng)目完美運(yùn)行。但是,筆者經(jīng)過如下修改,發(fā)現(xiàn)一點(diǎn)兒疑問。

/* 線程 1 的入口函數(shù) */
static void thread1_entry(void *parameter)
{
...
while (cnt < 10)
   {
       ...
       tick = rt_tick_get();
       rt_thread_mdelay(1000);
       tick = rt_tick_get();
   }
   ...
}

把延時(shí)時(shí)間增長(zhǎng),前后添加測(cè)時(shí)。多次運(yùn)行發(fā)現(xiàn) tick 值改變只有 300 (`rt_thread_mdelay(300)`)。這說明了線程響應(yīng) signal 后,處理了信號(hào)回調(diào)函數(shù)之后放棄了之前的延時(shí)!那么問題來了,應(yīng)用層想要的延時(shí)時(shí)間不足,應(yīng)用層知道嗎?答案是,*不知道!*

rt-thread 中阻塞函數(shù)列表

前一段時(shí)間在文章 rt-thread 那些你必須知道的幾類 api 里總結(jié)了 *禁止在中斷中調(diào)用*、*必須在任務(wù)調(diào)度器運(yùn)行以后才能使用*、*不能用在線程自己身上*的幾類 api。

可能還缺一種:哪些 api 會(huì)引起線程調(diào)度,使得當(dāng)前線程放棄 cpu 使用權(quán)——所有調(diào)用 `rt_schedule` 的函數(shù)都屬于這類。這里邊又分三種情況,一種是時(shí)間片耗盡讓出 cpu 使用權(quán);一種是釋放資源或者信號(hào)讓出 cpu 使用權(quán);還有一種是等待資源而被動(dòng)放棄 cpu。最后這種情況,是有目地的,往往希望有資源可用了之后從阻塞中恢復(fù)繼續(xù)運(yùn)行,如果線程從阻塞中恢復(fù)運(yùn)行但同時(shí)沒有資源可用是不是就烏龍了?以下的關(guān)注重點(diǎn)也是這類函數(shù)。

所有第三類引起線程調(diào)度的函數(shù)和上面的 `rt_thread_mdelay` 一樣,在 signal 面前可能遇到一樣的遭遇。大體上,分這么幾類:

  • 延時(shí)函數(shù)
  • 線程間同步機(jī)制函數(shù)
  • 線程間通信機(jī)制部分函數(shù)(signal除外)
  • posix 下的 select poll 等接口(可能使用了線程間同步和通信機(jī)制)

這幾類在遇到 signal 之后行為分別是什么樣的?

被阻塞函數(shù)遇到 signal 后什么反應(yīng)?

延時(shí)函數(shù)遇到 signal

這個(gè)前面已經(jīng)經(jīng)過測(cè)試的了,它會(huì)退出阻塞提前結(jié)束延時(shí),但是應(yīng)用層并不知道是達(dá)到延時(shí)時(shí)間還是有信號(hào)。

線程間同步通信機(jī)制函數(shù)遇到 signal

  • `rt_sem_take` 線程 error 非 RT_EOK (包括 RT_EINTR)直接返回線程錯(cuò)誤狀態(tài)
   /* do schedule */
   rt_schedule();
   if (thread->error != RT_EOK)
   {
       return thread->error;
   }
  • `rt_mutex_take` 考慮到了 signal 的影響,返回繼續(xù)阻塞等待 `time` 時(shí)間。這是 ipc 里唯一例外的一個(gè)。
               /* do schedule */
               rt_schedule();

               if (thread->error != RT_EOK)
               {
#ifdef RT_USING_SIGNALS
                   /* interrupt by signal, try it again */
                   if (thread->error == -RT_EINTR) goto __again;
#endif /* RT_USING_SIGNALS */

其它,其余的 ipc 都和 `rt_sem_take` 一樣。

完成量遇到 signal

`rt_completion_wait` 返回線程錯(cuò)誤狀態(tài)。

           /* do schedule */
           rt_schedule();
           /* thread is waked up */
           result = thread->error;

           level = rt_hw_interrupt_disable();
       }
   }
   ...

   return result;

select poll 等接口與 signal

因?yàn)槲募枋龇麑?duì)應(yīng)的設(shè)備不盡相同,設(shè)備底層實(shí)現(xiàn) `poll` 的方式可能也千差萬別,但是他們大概率是使用上面的線程間同步和通信機(jī)制了。

`poll` 實(shí)現(xiàn)過程調(diào)用個(gè)超時(shí)等待函數(shù) `poll_wait_timeout` ,它也沒有區(qū)分超時(shí)和信號(hào)兩種情況。

       rt_schedule();
       level = rt_hw_interrupt_disable();
   }

   ret = !pt->triggered;
   rt_hw_interrupt_enable(level);

   return ret;

我們發(fā)現(xiàn),`rt_sem_take` 結(jié)束了阻塞,并可能返回了 `RT_EINTR` ,而 `rt_mutex_take` 繼續(xù)了循環(huán)阻塞。

等待資源而被動(dòng)放棄 cpu 時(shí)怎么應(yīng)對(duì) signal 才合適?

現(xiàn)做以下約定,等待資源而被動(dòng)放棄 cpu 的線程在此約定下,當(dāng)有 signal 的時(shí)候會(huì)提前結(jié)束阻塞,返回應(yīng)用層,應(yīng)用層可以根據(jù)線程錯(cuò)誤狀態(tài)區(qū)別處理。

1. 復(fù)位線程錯(cuò)誤狀態(tài)為 `RT_EOK` 。
2. 調(diào)用 `rt_schedule` 進(jìn)行線程調(diào)度,線程被阻塞掛起。
3. 從 `rt_schedule` 恢復(fù)喚醒,有一定手段通知到應(yīng)用層(返回線程錯(cuò)誤狀態(tài)),應(yīng)用層可以區(qū)分出是因?yàn)橘Y源可用還是因?yàn)樾盘?hào)。

哪些 api 做到了以上這幾點(diǎn)呢?

```
rt_completion_wait
rt_sem_take
rt_event_recv
rt_mb_send_wait
rt_mb_recv
rt_mq_send_wait
rt_mq_recv
rt_data_queue_push
rt_data_queue_pop

rt_mp_alloc

哪些 api 沒有做到以上幾點(diǎn)?

```
rt_mutex_take
rt_thread_sleep
rt_thread_delay
rt_thread_delay_until
rt_thread_mdelay
rt_wqueue_wait

筆者曾經(jīng)在 gitee 上提交過一個(gè) [issue]( https://gitee.com/rtthread/rt-thread/issues/I44JNS ) ,當(dāng)時(shí)筆者隱隱中認(rèn)為 ipc 中的不一致行為總有些隱患,感覺所有的阻塞等待都應(yīng)該處理一下意外喚醒后的超時(shí)等待。卻沒意識(shí)到有什么意外情況可以讓這些函數(shù)從阻塞等待中提前退出。通過研究 signal 實(shí)現(xiàn)原理的過程中發(fā)現(xiàn),這種意外情況還有存在的,只是擔(dān)憂的問題重點(diǎn)變了,不是處理阻塞等待剩余時(shí)間,而是在 signal 的影響下通知應(yīng)用層的問題。

解決方案

有了上面的梳理,下面的修改方向就有了,改動(dòng)范圍也確定了。

  • 幾個(gè)延時(shí)函數(shù)返回 `thread->error` 代替目前的 `RT_EOK` ;
  • `rt_mutex_take` 去掉 `goto __again` 也返回 `thread->error` ;
  • `rt_wqueue_wait` 返回 `thread->error` 代替目前的 `RT_EOK` 。
  • `poll` 目前返回值是 >= 0 的,返回 0 可能是超時(shí),也可能是被信號(hào)中斷了。暫時(shí)不發(fā)表修改意見。

結(jié)束語

以上搜索不一定完整完全,但應(yīng)該包括了大部分受到影響的函數(shù)。如果看客有發(fā)現(xiàn)其它的 api 有不符合上述約定行為的,請(qǐng)留言告知,謝謝!

本人能力有限,文中難免有錯(cuò)誤。望各位同仁不吝賜教。

相關(guān)文章

rt-thread 優(yōu)化系列(0) SysTick 優(yōu)化分析

rt-thread 優(yōu)化系列(一) 之 過多關(guān)中斷

rt-thread 優(yōu)化系列(二) 之 同步和消息關(guān)中斷分析

rt-thread優(yōu)化系列(三)軟定時(shí)器的定時(shí)漂移問題分析


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

    關(guān)注

    11

    文章

    2773

    瀏覽量

    76539
  • IPC
    IPC
    +關(guān)注

    關(guān)注

    3

    文章

    337

    瀏覽量

    51772
  • signal
    +關(guān)注

    關(guān)注

    0

    文章

    110

    瀏覽量

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

    關(guān)注

    31

    文章

    1261

    瀏覽量

    39838
收藏 人收藏

    評(píng)論

    相關(guān)推薦

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

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

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

    漂移問題分析rt-thread 優(yōu)化系列信號(hào)對(duì) ipc 的影響
    發(fā)表于 07-26 14:56

    RT-Thread編程指南

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

    RT-Thread用戶手冊(cè)

    RT-Thread用戶手冊(cè)——本書是RT-Thread的編程手冊(cè),用于指導(dǎo)在RT-Thread實(shí)時(shí)操作系統(tǒng)環(huán)境下如何進(jìn)行編 程。
    發(fā)表于 11-26 16:16 ?0次下載

    RT-Thread隱藏的寶藏之completion

    completion 直接翻譯過來是完成,所以我更愿意稱 rt_completion 為 完成量。在 RT-Thread 的文檔中心 中講線程間通訊(IPC)時(shí),只介紹...
    發(fā)表于 01-25 19:27 ?0次下載
    <b class='flag-5'>RT-Thread</b>隱藏的寶藏之completion

    RT-Thread全球技術(shù)大會(huì):螢石研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會(huì):研發(fā)團(tuán)隊(duì)使用RT-Thread的技術(shù)挑戰(zhàn) ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 11:36 ?1269次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):螢石研發(fā)團(tuán)隊(duì)使用<b class='flag-5'>RT-Thread</b>的技術(shù)挑戰(zhàn)

    RT-Thread全球技術(shù)大會(huì):Kconfig在RT-Thread中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):Kconfig在RT-Thread中的工作機(jī)制 ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 14:49 ?1493次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):Kconfig在<b class='flag-5'>RT-Thread</b>中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):在RT-Thread上編寫測(cè)試用例

    RT-Thread全球技術(shù)大會(huì):在RT-Thread上編寫測(cè)試用例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:28 ?1438次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):在<b class='flag-5'>RT-Thread</b>上編寫測(cè)試用例

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

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

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

    RT-Thread 簡(jiǎn)介 作為一名 RTOS 的初學(xué)者,也許你對(duì) RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會(huì)逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?4457次閱讀
    <b class='flag-5'>RT-Thread</b>學(xué)習(xí)筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡(jiǎn)介

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

    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學(xué)習(xí)

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

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

    RT-Thread 代碼倉庫地址: ●? https://github.com/RT-Thread/rt-thread RT-Thread 5.0.2 版本發(fā)布日志詳情: ●? htt
    的頭像 發(fā)表于 10-10 18:45 ?1356次閱讀
    <b class='flag-5'>RT-Thread</b> v5.0.2 發(fā)布