RTThread學習筆記——線程間通訊學習

由通訊提出的問題編程

  在裸機編程的過程當中,咱們常常會遇到函數須要另外一些函數的數據信息,也就是通訊,這時咱們會怎麼作呢?進行裸機開發的同窗確定都會說:使用全局變量,經過指針實現之類。使用全局變量快捷且高效。  服務器

  可是在RTOS系統中,這會遇到一些問題:怎樣防止許多線程同時進行對這個變量的訪問?怎樣觀測通訊是否已經發生,從而進行通訊以後的工做?(例如:進行優先級轉換,或者進行數據的處理)若是有個線程比較磨蹭,通訊遲遲不發生,CPU豈不是要尷尬地等待很久。。多線程

  對於這些問題,操做系統給出了本身的通訊方法與函數供使用者調用,固然,也最好使用操做系統的通訊機制。函數

  

  咱們打開RTT 的IDE,而後打開內核的Setting,會看到RTT的一些設定:學習

  

  能夠看到,線程間通訊一欄,這就是RTT給開發者提供的通訊機制,在實際開發中,這些機制能夠知足絕大部分需求。RTT系統默認打開了信號量,互斥量,事件集,郵箱,消息隊列五種機制。網站


信號量:spa

二值信號量:操作系統

  在咱們的裸機開發過程當中,常常會使用一個變量:Flag,大多數時候,這個叫作Flag的變量會在0和1之間反覆橫跳,用於標記某一件事情是否發生,並常常被用於中斷。這個Flag就是一個信號量,實際上,它是咱們最常使用的通訊方式之一。線程

  在RTT系統中,信號量會被獲取或者釋放(由獲取/釋放函數實現),當它被獲取時,就爲0,當它被釋放,就爲1。這樣的信號量被稱爲二值信號量。指針

  舉一個例子(僞代碼):

static void xxx1()
{
    while(1)
    {
         /*一個傳感器採集一個特別複雜的數據,須要3S,不須要CPU參與*/
         xxx
    }
}

static void xxx2()
{
    while(1)
    {
         /*將這個數據交給CPU進行分析,數據無效就捨棄*/   
         xxx
      rt_thread_mdelay(xx)  } }

  在這個例子中,有兩個線程,線程2中,CPU一直在等待數據,但數據卻老是無效的(由於傳感器還沒采集到數據),這讓CPU一直在進行數據驗證,雖然CPU中間進行了一些延時,但仍然在無效數據上浪費了時間,這時,就須要信號量出馬了

 

  改良後數據以下(僞代碼):  

rt_sem_create(xxx);    //信號量建立函數,參數中默認爲1,表示是釋放的,具體參數不贅述

static void xxx1()
{
    while(1)
    {
         rt_sem_take(xxx)    //獲取信號量,這時信號量被置0

         /*一個傳感器採集一個特別複雜的數據,須要3S,不須要CPU參與*/
         xxx

         rt_sem_release(xxx)  //釋放信號量,這時信號量被置1
    }
}

static void xxx2()
{
    while(1)
    {
         rt_sem_take(xxx)    //獲取信號量,當信號量已經被其餘線程獲取,就進入阻塞態等待,等待時間自定,這裏不贅述

         /*將這個數據交給CPU進行分析,數據無效就捨棄*/   
         xxx

         rt_sem_release(xxx)  //釋放信號量
   rt_thread_mdelay(xx) 
    }
}        

  這裏咱們看到,當傳感器開始工做時,信號量已經被獲取了,這時進入線程二想要處理數據,就會進入阻塞態,讓出CPU去作其餘的事情,當傳感器得到數據後,就會釋放信號量,這時,線程二就從阻塞態中退出,從而去處理有效的數據。(注意:獲取信號量進行相關操做後應馬上釋放信號量,若是不進行釋放,可能會致使其餘線程沒法運行)

  通過這一番操做,無效數據不會被一次又一次的處理了,而是在傳感器得到數據後,CPU直接去處理有效的數據,節省了許多無效操做。

 

計數型信號量:

  計數型信號量與二值信號量相似,只不過範圍從二值的[0,1],變爲了[0,65535],這樣它就能夠被多個線程獲取,獲取的最大數目由使用者自定,使用的系統函數與二值信號量相同。

  計數信號量常常被用於控制一些公共資源的訪問數量,例如一個資源最多能夠被x個線程同時訪問,多於x時效率大大降低或者會出現錯誤(有點像網站服務器限制訪客數量)。

 


 

 

互斥量:

   互斥量是一種特殊的二值信號量,其與二值信號量的最大區別爲引入了優先級繼承機制。

  優先級繼承機制:若是一個高優先級的線程去申請一個已經被低優先級得到的互斥量,高優先級會進入到阻塞態,而持有這個互斥量的線程地位會瞬間與高優先級同樣,取得高優先級相同的優先等級,這就是「優先級繼承」

  這樣有什麼好處呢?這裏依然是一個栗子。

static void HIGH()
{
    xxx
}

static void MIDDLE()
{
    xxx
}

static void LOW()
{
    xxx
}

  假設有三個線程,優先度分別爲高,中,低。理所固然,開發者但願高優先級的越快處理越好,低優先級的則不是很緊要。

  這時,若是有個二值信號量,被低優先級(LOW)獲取。而後高優先級(HIGH)的也想要獲取這個信號量,因而進入了阻塞等待。

  可是當LOW準備用CPU運行時,MIDDLE卻發話了:我有更緊要的任務,你讓開。LOW小弟就被擠到了一邊,畢竟它是優先級最低的。

  這就產生了一個問題,開發者最但願運行的HIGH在等待信號量,而MIDDLE卻在運行(假設MIDDLE和HIGH無關聯,此時HIGH就要等待MIDDLE運行+LOW運行,而不是隻等待LOW運行),LOW在等待CPU讓出。這顯然違背了開發者「高優先級越快越好」的想法。

  

  怎樣解決這個問題,這時就引入互斥量來解決這個問題,當HIGH進入阻塞態以後,LOW瞬間「繼承」了HIGH的優先級,LOW小弟也暫時體驗了當大哥的感受,並把MIDDLE擠到一邊,快速的處理起了數據,並在處理完後變回原來的優先級,將互斥量釋放,HIGH得以繼續運行。這樣,經過暫時提升LOW的優先級,開發者所但願的HIGH處理越快越好的想法得以實現。

 

(暫時記錄信號量和互斥量的學習筆記,文中可能有些理解和想法有略微的誤差,請注意=))

相關文章
相關標籤/搜索