嵌入式系統(tǒng)架構(gòu)淺談——嵌入并發(fā)和資源管理的設(shè)計模式
時間:2021-08-19 16:03:34
手機看文章
掃描二維碼
隨時隨地手機看文章
[導(dǎo)讀]關(guān)注、星標(biāo)公眾號,直達精彩內(nèi)容來源:網(wǎng)絡(luò)素材?|ZeroMing222嵌入并發(fā),意味著多線程或者多任務(wù),基本上都是使用了系統(tǒng),linux系統(tǒng)或RTOS系統(tǒng)之類的實現(xiàn)。RTOS系統(tǒng)里任務(wù)的調(diào)度主要有搶占式和時間片調(diào)度兩種,具體的區(qū)別這里就不詳細(xì)說明了。此篇章包含了并發(fā)的一些術(shù)語,如...
關(guān)注、星標(biāo)公眾號,直達精彩內(nèi)容來源:網(wǎng)絡(luò)素材?| ZeroMing222
嵌入并發(fā),意味著多線程或者多任務(wù),基本上都是使用了系統(tǒng),linux系統(tǒng)或RTOS系統(tǒng)之類的實現(xiàn)。RTOS系統(tǒng)里任務(wù)的調(diào)度主要有搶占式和時間片調(diào)度兩種,具體的區(qū)別這里就不詳細(xì)說明了。此篇章包含了并發(fā)的一些術(shù)語,如并發(fā)性,臨界性,資源,死鎖等的概念。最好是詳細(xì)閱讀RTOS系統(tǒng)的書籍。
聲明:文章基于《C嵌入式編程設(shè)計模式》這本書,英文是Design?Patterns?for?Embedded?Systems in C。主要是做個筆記,并添加一點個人的理解,分享出來與各位探討。
嵌入并發(fā),意味著多線程或者多任務(wù),基本上都是使用了系統(tǒng),linux系統(tǒng)或RTOS系統(tǒng)之類的實現(xiàn)。RTOS系統(tǒng)里任務(wù)的調(diào)度主要有搶占式和時間片調(diào)度兩種,具體的區(qū)別這里就不詳細(xì)說明了。此篇章包含了并發(fā)的一些術(shù)語,如并發(fā)性,臨界性,資源,死鎖等的概念。最好是詳細(xì)閱讀RTOS系統(tǒng)的書籍。
聲明:文章基于《C嵌入式編程設(shè)計模式》這本書,英文是Design?Patterns?for?Embedded?Systems in C。主要是做個筆記,并添加一點個人的理解,分享出來與各位探討。
1.?嵌入并發(fā)和資源管理的設(shè)計模式
總共有8個模式,前兩個循環(huán)執(zhí)行模式和靜態(tài)優(yōu)先級模式,提供了兩個不同的方法來調(diào)度任務(wù)或線程。接下來3個模式臨界區(qū)模式,守衛(wèi)調(diào)用模式和隊列模式,為了使解決在多任務(wù)環(huán)境下串行訪問資源的問題。匯合模式講的是多任務(wù)以不同的方式進行同步。最后兩個模式是關(guān)注預(yù)防死鎖問題。希望下面的模式能夠各位一點啟發(fā)。1.1 循環(huán)執(zhí)行模式
循環(huán)模式有非常簡單的方式調(diào)用多個任務(wù)的特點,允許所有的任務(wù)有同等機會運行,但是不能及時響應(yīng)緊急事件。一般在資源少的系統(tǒng)里面使用,避免了RTOS的開銷,也不需要復(fù)雜的任務(wù)調(diào)度。簡單就是最大的優(yōu)點。1.1.1 模式結(jié)構(gòu)
CyclicExecutive有一個controlLoop()函數(shù),可以反復(fù)調(diào)用每個任務(wù)的run操作。也需要等待任務(wù)的結(jié)束再調(diào)用下一個任務(wù)。1.1.2 角色
1.1.2.1 抽象任務(wù)(AbstractCEThread)通過聲明run()函數(shù)為線程提供接口。它是用來循環(huán)執(zhí)行的任務(wù)函數(shù)。1.1.2.2 循環(huán)控制(CyclicExecutive)這個類用于循環(huán)執(zhí)行每個任務(wù)。此外也有全局棧和任務(wù)本身需要的靜態(tài)數(shù)據(jù)。模式的一個變體是時間觸發(fā)循環(huán)執(zhí)行,在這個變體中,CyclicExecutive設(shè)置使用CycleTimer來開啟每個周期。也就是使用這個變體可以在周期類執(zhí)行每個函數(shù)。1.1.2.3 循環(huán)定時器(CycleTimer)圖中有表示帶有“0,1”,這個定時器是可選的。當(dāng)定時器時間到時,可以調(diào)用中斷或者返回TRUE給hasElapsed()函數(shù)。CyclicExecutive將調(diào)用start()為下一個周期開始計時。1.1.2.4 具體任務(wù)實現(xiàn)(ConcreteCEThread)每個ConcreteCEThread都有自己的run()函數(shù),用于具體的任務(wù)實現(xiàn)。1.1.3 效果
如前所述,該模式優(yōu)點在于簡單,一方面很難導(dǎo)致調(diào)度程序錯誤,另一方面對緊急事件響應(yīng)不足,使得僅使用在內(nèi)存小的設(shè)備。還有缺點是,任務(wù)間的通訊會值得考慮,比如一個任務(wù)需要另一個任務(wù)的數(shù)據(jù),那么數(shù)據(jù)只能保存在全局的內(nèi)存或共享資源中。我們盡量不要定義太多的全局變量,否則會難以管理維護,和造成內(nèi)存的浪費。1.1.4 實現(xiàn)
該模式的實現(xiàn)非常簡單。在大多數(shù)情況下,循環(huán)執(zhí)行可能僅是應(yīng)用的main()函數(shù)中調(diào)用。?1.2 靜態(tài)優(yōu)先級模式
大多數(shù)的實時操作系統(tǒng)都是靜態(tài)優(yōu)先級模式。所以想要使用這個模式直接移植RTOS系統(tǒng)就好了。這里的模式復(fù)雜度和完整度是無法比得上RTOS系統(tǒng)的,不過閱讀這里也可以使你對RTOS的任務(wù)調(diào)度有所了解,因為這是基于這個框架的。靜態(tài)優(yōu)先級模式能夠為任務(wù)劃分優(yōu)先級,能夠更好響應(yīng)高優(yōu)先級時間。1.2.1 模式結(jié)構(gòu)
除了右下角AbstraceStaticThread,SharedResource,ConcreteStaticThread這三個類,其他一般是由RTOS實現(xiàn)。1.2.2 角色
1.2.2.1 抽象線程(AbstraceStaticThread)是一個抽象類,提供run()函數(shù)給調(diào)度器運行。1.2.2.2 具體線程(ConcreteStaticThread)ConcreteThread作為AbstraceStaticThread具體實現(xiàn)run()函數(shù)。1.2.2.3 互斥鎖(Mutex)是一個互斥的信號量類,用來串行訪問SharedResource。當(dāng)一個任務(wù)調(diào)用了互斥量的lock()函數(shù),其他任務(wù)嘗試鎖定的同一個互斥量時候,會被阻塞,直到互斥量的解鎖或超時退出。1.2.2.4 隊列(PriorityQueue)PriorityQueue是根據(jù)優(yōu)先級,對指向StaticTaskControlBlock的指針進行排序,也就是說隊列里存儲的其實每個線程的排隊。一般在RTOS系統(tǒng)里,存在不止一個隊列,有就緒隊列,阻塞隊列等,調(diào)度器會從就緒隊列取出第一個執(zhí)行。1.2.2.5 資源(SharedResource)該資源可能在一個或多個線程里共享,需要保證資源的正常,在下面模式會說明資源共享的問題。1.2.2.6 棧(Stack)每個AbstraceStaticThread都有一個棧用于返回地址和傳遞參數(shù)。1.2.2.7 調(diào)度器(StaticPriorityScheduler)最簡單的法則:總是運行最高優(yōu)先級的準(zhǔn)備線程。RTOS系統(tǒng)里,任務(wù)創(chuàng)建,任務(wù)切換等都需要經(jīng)過調(diào)度器。任務(wù)創(chuàng)建成功后,會把任務(wù)按優(yōu)先級加入到就緒列表中,任務(wù)掛起就會加入到掛起列表。系統(tǒng)有個滴答時鐘中斷或其他能夠進行任務(wù)切換,查找下一個運行的任務(wù)可以有通用方法,就是從就緒列表取。另一種是硬件方法,使用處理器自帶的硬件指令來實現(xiàn),需要硬件本身支持。1.2.2.8 程序控制塊(StaticTaskControlBlock)包含了它相應(yīng)的AbstraceStaticThread對象的調(diào)度信息。有線程的優(yōu)先級,默認(rèn)開始地址,目前地址,只要線程還在沒被銷毀,這個塊就會伴隨著存在。1.2.3 效果
靜態(tài)優(yōu)先級模式能夠?qū)κ录峁┘皶r響應(yīng),可以對CPU大程序優(yōu)化,避免單線程因等待時占用CPU這種浪費。因RTOS系統(tǒng)的支持,線程間通訊也有很多保證,郵箱,信號量機制,避免了過多的全局變量。1.1.4 實現(xiàn)
最好的方式是直接移植成熟的RTOS系統(tǒng)來實現(xiàn)。使用這種模式,需要對前期開發(fā)有個設(shè)計,對內(nèi)存分配,優(yōu)先級分配等因素,需要在程序開發(fā)前有個規(guī)劃,否則可能會造成后面存在各種問題。復(fù)雜度比單線程的高,所以需要你有個深入的理解,才能對RTOS系統(tǒng)運用掌握,但是也不用害怕,RTOS始終還是中小的系統(tǒng),有時間可以研究源碼,RTOS對指針,數(shù)據(jù)結(jié)構(gòu)的運用非常的成熟高效。?1.3 臨界區(qū)模式
臨界區(qū)模式是任務(wù)協(xié)調(diào)最簡單的方式。它直接禁止了任務(wù)的切換,在臨界區(qū)內(nèi)安全訪問之后,再退出臨界區(qū)。1.3.1 模式結(jié)構(gòu)
模式結(jié)構(gòu)非常簡單,在進入臨界區(qū)后才訪問資源。調(diào)度程序不參與臨界區(qū)的開啟和結(jié)束過程,知識提供服務(wù)禁止和重啟任務(wù)切換。如果調(diào)度系統(tǒng)不提供,則臨界區(qū)能夠在硬件級別使用C的asm直接開關(guān)中斷處理。1.3.2 角色
1.3.2.1 臨界區(qū)(CRShaaredResource)使用這個元素來禁止任務(wù)切換,以防止任務(wù)同時訪問資源。這個例子里,受保護資源是Value屬性,相關(guān)的服務(wù)都必須使用臨界區(qū)來保護,setValue()和getValue()函數(shù)必須獨立實現(xiàn)臨界區(qū)。1.3.2.2 任務(wù)集合(TaskWithSharedResource)這個元素代表所有想要訪問共享資源的任務(wù)集。這些任務(wù)并不知道保護資源的方法,因為它被封裝在共享資源內(nèi)。1.3.3 效果
模式特點就是禁止調(diào)度任務(wù)的切換,更嚴(yán)格的,禁止所有的中斷。注意的是,一旦元素離開了臨界區(qū),將重啟任務(wù)切換,另外使用了臨界區(qū),就注定會影響到其他任務(wù)的時序,所以盡量保證臨界區(qū)的時間不要長。1.3.4 實現(xiàn)
絕大多數(shù)的RTOS系統(tǒng)直接提供函數(shù),調(diào)用即可。?1.4 守衛(wèi)調(diào)用模式
守衛(wèi)調(diào)用模式提供了鎖定的機制串行訪問,可以阻止當(dāng)鎖定后來自其他線程的調(diào)用資源。在RTOS系統(tǒng)里,直白的說就是信號量。使用這個模式可能會導(dǎo)致優(yōu)先級導(dǎo)致,或死鎖的問題發(fā)生。1.4.1 模式結(jié)構(gòu)
在模式下,多個PreemptiveTasks通過他們的函數(shù)訪問GuardeResource。當(dāng)一個線程調(diào)用一個正在鎖定的信號量時,調(diào)度服務(wù)會把該線程加入到阻塞隊列中,等待當(dāng)那個信號量釋放或超時時,解除阻塞。調(diào)度服務(wù)必須作為臨界區(qū)實現(xiàn)信號量的lock()功能,以防止可能的競爭條件。1.4.2 角色
1.4.2.1 共享資源(GuardedResource)在這個類中使用互斥信號量來互斥訪問。在訪問資源之前,執(zhí)行與Semaphore實例關(guān)聯(lián)的lock()函數(shù)。如果Semaphore是在非鎖定狀態(tài),則變?yōu)殒i定;如果在鎖定狀態(tài),則Semaphore會調(diào)度復(fù)位發(fā)信號阻塞這個任務(wù)。1.4.2.2 任務(wù)(PreemptiveTask)訪問共享資源的任務(wù)。1.4.2.3 互斥信號量(Semaphore)它串行訪問GuardedResource。lock()函數(shù)是用于訪問資源之前,release()函數(shù)是訪問資源后,調(diào)用釋放信號量。1.4.3 效果
該模式提供及時訪問資源,并同時阻止多個能夠?qū)е聰?shù)據(jù)損壞和系統(tǒng)錯誤行為的同時訪問。如果資源沒有上鎖,那么訪問資源并不會遭受到延遲。1.4.4 實現(xiàn)
通過使用RTOS提供的信號量函數(shù)。一般都會提供創(chuàng)建信號量,摧毀信號量,上鎖,解鎖的接口。?1.5 隊列模式
隊列模式是任務(wù)異步通訊常見的實現(xiàn)。它提供了在任務(wù)間的通訊方式。發(fā)送者將消息隊列Cyrus隊列中,一段時間過后,接受者從隊列取出消息。它也可以實現(xiàn)了串行訪問共享資源,把訪問消息排隊,并且在稍后處理,這避免了共享資源同時訪問的問題。1.5.1 模式結(jié)構(gòu)
QUEUE_SIZE聲明決定隊列能容納最大的元素數(shù)目。必須足夠大來處理最差的情況,也不要太大以免內(nèi)存的浪費。1.5.2 角色
1.5.2.1 消息(Message)它可以任何東西,是簡單的數(shù)據(jù)值,或發(fā)送消息的詳細(xì)數(shù)據(jù)報結(jié)構(gòu)。1.5.2.2 消息隊列(MessageQueue)MessageQueue是QTasks間交換的信息存儲。提供了getNextIndex()函數(shù)來運行計算下一個有效的索引值。insert()函數(shù)在頭部位置將Message插入到隊列中并更新頭索引。remove()函數(shù)可以用于刪除最舊的消息。iFull(),isEmpty()兩個用來檢測隊列是否已滿,是否為空。1.5.2.3 互斥信號量(Mutex)是互斥信號量,如靜態(tài)優(yōu)先級模式中的描述類似。1.5.2.4 任務(wù)(QTask)QTask是MessageQueue的客戶,要么調(diào)用insert()插入新消息,要么調(diào)用remove()訪問最早的數(shù)據(jù)。1.5.3 效果
當(dāng)數(shù)據(jù)在任務(wù)間傳遞,隊列模式十分好用?;コ饬靠梢源_保隊列本身不會由于同時訪問造成損壞。相比守衛(wèi)調(diào)用模式,隊列模式接收數(shù)據(jù)不是很及時。1.5.4 實現(xiàn)
隊列的最簡單實現(xiàn)是消息元素數(shù)組。有簡單的優(yōu)點,也會有靈活性不足,占用空間固定等缺陷。更多是使用鏈表的方式來實現(xiàn)隊列。MessageQueue還可以添加多個緩沖區(qū),每個優(yōu)先級一個隊列,這樣實現(xiàn)優(yōu)先級策略,或者基于消息優(yōu)先級,通過插入元素隊列中實現(xiàn)。在復(fù)雜的系統(tǒng)中,預(yù)測最佳隊列大小是不可行的,如果使用數(shù)組實現(xiàn)隊列的方式,會存在超出容量的問題。在這種情況下,可以額外使用一個緩沖隊列在作為臨時存儲。?1.6 匯合模式
任務(wù)必須以不同的方式同步。發(fā)生同步可能是共享單一資源,或者等待信號量等造成,這些隊列模式和守衛(wèi)調(diào)用模式都能夠?qū)崿F(xiàn)。但是如果同步需要的條件更加復(fù)雜呢?匯合模式就是解決這個問題。當(dāng)所有的任務(wù)都滿足同步條件時,才能繼續(xù)運行。1.6.1 模式結(jié)構(gòu)
需要同步的線程至少2個,同時擁有唯一的Rendezvous。1.6.2 角色
1.6.2.1 聚合(Rendezvous)用于管理同步。它通過兩個方式:reset()函數(shù)重置同步標(biāo)準(zhǔn)為初始條件。synchronize()函數(shù),當(dāng)任務(wù)想要同步時調(diào)用這個方法。如果不滿足標(biāo)準(zhǔn),則任務(wù)阻塞。這個通??梢允褂糜^察者模式或守衛(wèi)調(diào)用模式實現(xiàn)。1.6.2.2 計數(shù)信號量(Semaphore)這個通常是計數(shù)信號量,有創(chuàng)建,摧毀,上鎖和釋放標(biāo)準(zhǔn)鎖的接口函數(shù)。用于存儲當(dāng)前所有任務(wù)滿足同步條件的數(shù)量。當(dāng)?shù)扔陬A(yù)設(shè)值時,同步條件滿足。1.6.2.3 線程(SynchronizingThread)代表使用Rendezvous同步的每個線程。1.6.3 效果
在這個模式中,兩個或更多的任務(wù)都同時滿足某個條件時,才能繼續(xù)運行或調(diào)用回調(diào)函數(shù)。1.6.4 實現(xiàn)
該模式可以通過前面的觀察者模式,或者守衛(wèi)調(diào)用模式實現(xiàn)。如果使用的是觀察者模式,則任務(wù)必須使用函數(shù)的地址注冊,當(dāng)滿足同步條件時調(diào)用。如果使用的是守衛(wèi)調(diào)用模式,則每個Rendezvous對象擁有唯一的信號量,任務(wù)想同步時調(diào)用synchronize()函數(shù)告知給Rendezvous,當(dāng)Rendezvous滿足同步條件時,釋放信號量,并且任務(wù)隨后根據(jù)通常的調(diào)度策略全部釋放運行。?1.7 同時鎖定模式
首先不考慮軟件自身導(dǎo)致的錯誤,發(fā)生死鎖需要滿足4個條件:- 互斥鎖資源。
- 當(dāng)請求其他資源時,一些資源已經(jīng)鎖定。
- 當(dāng)資源鎖定是允許搶斷。
- 存在循環(huán)等待條件。