- VxWorks設(shè)備驅(qū)動開發(fā)詳解
- 曹桂平等編著
- 4356字
- 2019-01-09 15:53:25
2.3 VxWorks任務(wù)間通信策略
無論內(nèi)存是否通過MMU機制進(jìn)行管理,每個任務(wù)都有自己的內(nèi)存空間。通過MMU機制進(jìn)行管理時,內(nèi)存空間被分為兩個區(qū)域:虛擬內(nèi)存區(qū)域和物理內(nèi)存區(qū)域。此時程序中使用的是虛擬內(nèi)存地址,當(dāng)一個程序需要訪問外部內(nèi)存時,一般CPU中MMU硬件單元會自動完成虛擬地址到物理地址的轉(zhuǎn)換。基于MMU機制的操作系統(tǒng),任務(wù)運行的代碼中使用虛擬地址。由于需要通過虛擬地址到物理地址的變換,故不同任務(wù)之間虛擬地址的重疊不會造成任何問題,而實際上,幾乎所有的操作系統(tǒng)在MMU機制下將系統(tǒng)內(nèi)所有任務(wù)的虛擬地址空間都設(shè)置為完全重疊的區(qū)域,如Linux操作系統(tǒng)下一個任務(wù)(進(jìn)程)的虛擬地址空間范圍為0~3GB,最高1GB被內(nèi)核和所有的任務(wù)共享(即內(nèi)核代碼使用的虛擬地址空間)。
不同的任務(wù)具有完全重疊的虛擬地址空間并不會對任務(wù)的實際運行造成任何影響,因為不同的任務(wù)雖然具有相同的虛擬地址,但是通過MMU的映射都被映射到不同的物理地址,而物理地址才是訪問外部實際RAM時使用的地址。由于不同的任務(wù)具有完全相同的虛擬地址,故為了保證任務(wù)間不相互影響,每個任務(wù)都具有自己的內(nèi)存映射表,這個映射表作為任務(wù)自身組成的一個關(guān)鍵部分而存在。如圖2-1所示,表示了兩個不同任務(wù)地址的映射關(guān)系。

圖2-1 虛擬地址空間到物理地址空間的映射
由于物理地址空間有限,故對于暫時不使用的物理頁面可以先將其置換到硬件緩沖區(qū)中,即通常所述的交換區(qū),從而讓出相應(yīng)的物理頁面供其他任務(wù)使用。使用這種交換的方法,從表面上或者從任務(wù)使用頁面的角度表現(xiàn)為一個比實際內(nèi)存設(shè)備容量大得多的物理存儲。對于無MMU機制下的任務(wù)而言,虛擬地址就是物理地址,此時不同任務(wù)的地址空間必須嚴(yán)格隔離開(當(dāng)然除了刻意使用共享內(nèi)存),保證不同任務(wù)間不會造成相互影響。
結(jié)合以上的說明,對于任務(wù)間通信,其本質(zhì)就是在使用共享物理內(nèi)存的機制。雖然手冊上將內(nèi)核提供的任務(wù)間通信機制與共享內(nèi)存機制區(qū)分開來,只把用戶層次的諸如全局變量之類的使用方式作為共享內(nèi)存來看,但是從操作系統(tǒng)底層來看,所有的任務(wù)間通信實現(xiàn)方法的內(nèi)在本質(zhì)都是共享物理內(nèi)存。
VxWorks內(nèi)核本身主要提供了5種任務(wù)間通信的機制:信號量、消息隊列、管道、網(wǎng)絡(luò)Socket、信號機制。這幾種機制無一例外地都是在使用共享物理內(nèi)存機制(可以將網(wǎng)絡(luò)通信暫且也看做是一種廣義上的內(nèi)存共享),只不過這塊共享的內(nèi)存由內(nèi)核進(jìn)行管理,任務(wù)無法直接進(jìn)行訪問,必須通過內(nèi)核提供的接口函數(shù)進(jìn)行訪問,這就提供了一種保護(hù)和管理機制,使得任務(wù)間通信安全有序地進(jìn)行。
2.3.1 信號量
信號量的主要用途是互斥和同步。互斥主要保護(hù)資源,即某個時刻只允許有一個任務(wù)在使用該資源。由于使用該資源的潛在用戶可能很多,故信號量此時此地就作為一把“鑰匙”,要使用該資源的任務(wù),必須首先取得這把鑰匙,方可進(jìn)行資源的使用,否則就等待。同步則是任務(wù)間協(xié)同完成某一項共同工作的機制,典型的例子即一個任務(wù)產(chǎn)生資源,另一個任務(wù)使用資源,使用任務(wù)的資源平時處于等待狀態(tài),等待產(chǎn)生資源的任務(wù)完成其資源的生成,而一旦資源產(chǎn)生完畢,此時產(chǎn)生資源的任務(wù)就會觸發(fā)同步信號量,讓等待使用資源的任務(wù)啟動(即喚醒)其處理資源的工作。
信號量的底層實現(xiàn)可以簡單地看做是一個內(nèi)核維護(hù)的全局變量,對于用于互斥機制的信號量,這個內(nèi)核全局變量初始化為1,當(dāng)一個任務(wù)需要訪問該信號量保護(hù)的資源時,其首先檢查這個內(nèi)核全局變量的值是否為1,如非1,則表示已存在其他任務(wù)在使用資源,就等待;如為1,表示資源當(dāng)前可被訪問,則這個任務(wù)首先將這個內(nèi)核全局變量的值設(shè)置為0,阻止其他任務(wù)的訪問,而自身就可以安全地使用該資源。此處的一個漏洞是,在當(dāng)前任務(wù)修改內(nèi)核全局變量的同時,另一個任務(wù)可能同時在檢查這個全局變量的值,很可能造成另一個任務(wù)檢查到全局變量值為1后,當(dāng)前任務(wù)才完成全局變量0值的設(shè)置,此時就有兩個任務(wù)在使用資源,造成內(nèi)核狀態(tài)的不一致,極端情況下,將造成整個系統(tǒng)的崩潰。內(nèi)核對這種情況進(jìn)行了特殊處理,一般是將變量的改變操作作為一個原子操作(如x86下提供的Lock指令)完成。這也是內(nèi)核提供的任務(wù)間通信機制和用戶層任務(wù)間通信機制的根本區(qū)別:內(nèi)核提供的機制已經(jīng)從根本上保證了足夠的安全性。
基于各種資源不同的使用方式,VxWorks信號量機制具體提供了三種信號量:通用信號量、互斥信號量、資源計數(shù)信號量。通用信號量既可用于同步,也可用于資源計數(shù),此時資源數(shù)通常為1(當(dāng)資源數(shù)為1時,也可以稱之為互斥)。互斥信號量針對在使用過程中的一些具體問題(如優(yōu)先級反轉(zhuǎn))做了優(yōu)化,更好地服務(wù)于任務(wù)間互斥需求;資源計數(shù)信號量用于資源數(shù)較多,同時可供多個任務(wù)使用的場合。
2.3.2 消息隊列
消息隊列內(nèi)核實現(xiàn)上實際是一個結(jié)構(gòu)數(shù)組,數(shù)組大小和數(shù)組中元素的容量在創(chuàng)建消息隊列時被確定。在創(chuàng)建消息隊列時指定的另外一個參數(shù)是消息隊列滿時任務(wù)等待基于的策略:FIFO或者優(yōu)先級排序。消息隊列是VxWorks內(nèi)核提供的任務(wù)間傳遞較多信息的一種機制,不過這種機制存在很大的局限性,即每個消息的最大長度是固定的。當(dāng)然,在這個最大長度范圍內(nèi)從用戶層而言是可變的,但是對于內(nèi)核維護(hù)而言,所有的消息都具有相同的長度,因為無論實際消息的長度如何,內(nèi)核都將按最大長度分配內(nèi)存空間。當(dāng)然,如果對每個消息都采用動態(tài)內(nèi)存分配方式,可以消除最大長度限制,但是這并不是VxWorks提供的消息機制。VxWorks內(nèi)核提供的消息機制在創(chuàng)建消息隊列時就必須指定單個消息的最大長度以及消息的數(shù)量,在消息隊列成功創(chuàng)建后,這些參數(shù)都是固定不變的。我們可以如此想象內(nèi)核對于消息隊列的實現(xiàn),在消息隊列創(chuàng)建之時,內(nèi)核分配一個大小為單個消息最大長度與消息數(shù)量乘積的內(nèi)存區(qū)域,可以將此看做是一個數(shù)組,數(shù)據(jù)元素個數(shù)為消息數(shù)量,每個元素的大小為單個消息最大長度。
當(dāng)用戶發(fā)送一個消息時,內(nèi)核將消息內(nèi)容存入數(shù)組中下一個空閑元素中,用戶讀取消息時,將讀取數(shù)組中下一個非空元素,底層基本實現(xiàn)為一個環(huán)形緩沖區(qū)。VxWorks最多只區(qū)分兩個優(yōu)先級的消息,對于高優(yōu)先級的消息將從數(shù)組開始處存儲,對于普通優(yōu)先級的消息將從數(shù)組尾部開始存儲,而讀取時從數(shù)組頭部開始讀取,從而保證高優(yōu)先級的消息優(yōu)先被傳遞。
當(dāng)然,以上只是一種簡單的類比,有助于讀者理解VxWorks內(nèi)核對于消息隊列的實現(xiàn)。由于消息隊列在創(chuàng)建時指定了消息數(shù)量,一旦任務(wù)傳遞的消息總數(shù)大于這個數(shù)量,那么傳遞消息的任務(wù)則需要等待,即將任務(wù)暫時設(shè)置為掛起狀態(tài),并統(tǒng)一掛起到一個內(nèi)核分配的專門附屬于對應(yīng)消息隊列的任務(wù)隊列中,在任務(wù)被放入這個任務(wù)隊列時,需要依據(jù)一定的策略,這個策略也是在消息隊列創(chuàng)建時指定,可以是FIFO,也可以是基于優(yōu)先級。FIFO方式即任務(wù)將以先進(jìn)先出的方式掛入到隊列中,如果消息隊列中空出一個元素可供傳遞消息,那么最早掛入隊列的任務(wù)將得到消息傳遞權(quán);而基于優(yōu)先級的任務(wù)隊列在任務(wù)掛起時,將根據(jù)優(yōu)先級將任務(wù)插入到隊列中,如此當(dāng)消息隊列可用時,最高優(yōu)先級的任務(wù)將優(yōu)先得到消息傳遞權(quán)。
2.3.3 管道
管道相比消息隊列提供了一種更為流暢的任務(wù)間信息傳遞機制。消息隊列對于每個消息的大小存在限制,而且必須將信息分批打包,而管道可以像文件那樣進(jìn)行讀寫,是一種流式消息機制,其提供的基本操作方式類似于對一個文件的讀寫,支持Select函數(shù),所以,可以對多個管道進(jìn)行信息監(jiān)測。管道在底層實現(xiàn)上是一種更直接的共享物理內(nèi)存機制。信號量和消息隊列還需要對傳遞的數(shù)據(jù)進(jìn)行某種方式的封裝,而管道不對傳遞信息做任何包裝,直接分配一塊連續(xù)的內(nèi)存空間作為任務(wù)間信息交互的中轉(zhuǎn)站。傳統(tǒng)意義上的管道分為兩種:命名管道和非命名管道。通常,任務(wù)間通信使用的都是命名管道。非命名管道使用在線程意義上,如父子進(jìn)程,進(jìn)程關(guān)系密切,且某些變量存在繼承關(guān)系,如文件描述符,一般無法使用在兩個執(zhí)行路線完全不同的任務(wù)之間。
VxWorks內(nèi)核提供的管道機制在創(chuàng)建時如同消息隊列也要指定一個消息數(shù)量以及單個消息的最大長度,事實上,VxWorks提供的管道機制在底層實現(xiàn)上完全基于消息隊列,用戶層使用上完全類似于對一個文件的操作,但是對于每次讀寫的字符數(shù)存在最大長度限制,這個限制就是管道創(chuàng)建時指定的最大消息長度。由于管道底層實現(xiàn)上是基于消息隊列的,故管道只是在應(yīng)用層進(jìn)行了文件系統(tǒng)層次的封裝,可以支持open、write、read、close等普通文件操作行為,文件系統(tǒng)層次下的層次為字符驅(qū)動層,提供pipe_open、pipe_write、pipe_read、pipe_close等響應(yīng)函數(shù),字符驅(qū)動層之下就是消息隊列實現(xiàn)函數(shù),諸如msgQReceive、msgQSend等函數(shù)。所以,本質(zhì)上講,VxWorks下的管道機制只是在消息隊列之上提供了文件系統(tǒng)層次的支持,其本質(zhì)上還是一個消息隊列,每次read、write(讀、寫)的最大數(shù)據(jù)長度受限,且read、write連續(xù)調(diào)用的次數(shù)受限,即如果連續(xù)調(diào)用read,而無對應(yīng)的write操作,內(nèi)核維護(hù)的消息隊列為空,此時read任務(wù)將掛起等待。注意:基于管道的消息隊列任務(wù)等待策略是基于FIFO方式的。
2.3.4 網(wǎng)絡(luò)套接字Socket
Socket是一種特殊的任務(wù)間通信機制,其特殊之處在于通信的任務(wù)雙方不需要限制在同一臺PC上,可以是聯(lián)網(wǎng)的任何兩臺計算機上的兩個任務(wù)。由于傳遞的信息需要通過非穩(wěn)定的網(wǎng)絡(luò)介質(zhì),故用戶需要指定信息傳輸策略:是否要求數(shù)據(jù)可靠。通常而言,使用Socket機制進(jìn)行信息傳遞的兩個任務(wù)間大多使用在批量數(shù)據(jù)的傳輸上,但也有進(jìn)行控制信息傳輸?shù)摹ocket通信雖然底層實現(xiàn)相比其他機制要復(fù)雜得多,但這些都是操作系統(tǒng)實現(xiàn)的一部分,在用戶使用層次上,與以上討論的其他三種機制沒有區(qū)別。用戶只需遵循一套規(guī)定的操作接口,即可完成不同主機上兩個任務(wù)間的信息傳輸。
Socket機制下的通信由于涉及不同主機,故傳輸方式從根本上區(qū)別于其他任務(wù)間通信機制,其底層實現(xiàn)上由網(wǎng)絡(luò)棧加網(wǎng)卡驅(qū)動組成,網(wǎng)卡驅(qū)動完成傳輸介質(zhì)上(如雙絞線)數(shù)據(jù)的接收,通過網(wǎng)絡(luò)棧的層層剖析,最后將傳遞的純數(shù)據(jù)暫存于內(nèi)核空間供任務(wù)讀取,發(fā)送方任務(wù)發(fā)送的信息經(jīng)過網(wǎng)絡(luò)棧的層層封裝,暫存于內(nèi)核空間,依次按序地通過網(wǎng)卡驅(qū)動最終發(fā)送到網(wǎng)絡(luò)傳輸介質(zhì)上。由于內(nèi)核提供的暫存空間有限,故無論是發(fā)送方還是接收方,都有數(shù)據(jù)速率的限制。
2.3.5 任務(wù)間通信的特殊機制:信號
信號不是信號量,二者不是一個概念。信號量是一種任務(wù)間互斥和同步機制,而信號則用于通知一個任務(wù)某個事件的發(fā)生。一個信號產(chǎn)生后,對應(yīng)任務(wù)暫停當(dāng)前執(zhí)行流程,轉(zhuǎn)去執(zhí)行一個特定的函數(shù)進(jìn)行處理。信號機制有些類似于中斷,也可以將信號看做是一種用戶層提供的軟件中斷機制(區(qū)別于CPU本身提供的軟件中斷指令)。這種用戶層軟件中斷機制相比硬件中斷和中斷指令而言具有較長的延遲時間,即從信號產(chǎn)生到信號的處理之間大多將經(jīng)歷較長的延遲。
VxWorks下的信號處理有些特別,當(dāng)一個任務(wù)接收到一個信號時,在這個任務(wù)下一次被調(diào)度運行之時進(jìn)行信號的處理(即調(diào)用相關(guān)信號處理函數(shù))。事實上,由于VxWorks在退出內(nèi)核函數(shù)時都會進(jìn)行任務(wù)調(diào)度,故一個任務(wù),無論是否是當(dāng)前執(zhí)行的任務(wù),都將在被調(diào)度運行時執(zhí)行信號的處理。通用操作系統(tǒng)上對于某些信號將不允許用戶修改其默認(rèn)處理函數(shù),如SIGKILL、SIGSTOP,然而VxWorks操作系統(tǒng)中可以對任何信號的處理函數(shù)進(jìn)行更換。
- 單片機基礎(chǔ)及應(yīng)用項目式教程
- 用Proteus可視化設(shè)計玩轉(zhuǎn)Arduino
- MC9S12XS單片機原理及嵌入式系統(tǒng)開發(fā)
- 單片機應(yīng)用項目化教程
- 51單片機逆向?qū)W習(xí)實戰(zhàn)教程(電子設(shè)計與嵌入式開發(fā)實踐叢書)
- 單片機原理與應(yīng)用:基于Keil+Proteus
- STM32單片機全案例開發(fā)實戰(zhàn)
- 零起點學(xué)Proteus單片機仿真技術(shù)
- ANSYS Workbench 17.0有限元分析從入門到精通
- 基于STM32的嵌入式系統(tǒng)設(shè)計與實踐
- 嵌入式Linux與物聯(lián)網(wǎng)軟件開發(fā):ARM處理器開發(fā)自學(xué)教程
- 單片機原理與應(yīng)用技術(shù)
- AVR單片機原理與應(yīng)用實例
- 單片機開發(fā)從入門到實踐
- 嵌入式系統(tǒng):基于項目的分析和設(shè)計