實(shí)時性迷思(1) —— “快是優(yōu)點(diǎn)么?”
【序】

也就是經(jīng)過那一次,我突然發(fā)現(xiàn)自己之前對實(shí)時性的認(rèn)知可謂徒有其表,甚至從未做對實(shí)時性模型本身的定量分析——所幸,那次研究報告如期交付,工作變動也如愿以償。然而,3年后我發(fā)現(xiàn)“我又雙叕天真了”——那是有一次,我正跟人討論嵌入式基本范式,就突然一個瞬間,腦海中原本毫不相關(guān)的一些模型猛地被聯(lián)系到了一起(音效請腦補(bǔ)):

我甚至本能的立即意識到:之前自己在某篇文章中“言之鑿鑿”的推論過程其實(shí)存在巨大漏洞——當(dāng)然,那本書從未出版過,而且會閑到對我進(jìn)行深究的人估計也沒有幾個。


。回頭看來,根據(jù)我的經(jīng)驗(yàn)以及與朋友討論的結(jié)果,大致認(rèn)為大部分人對實(shí)時性的認(rèn)知過程通常會分以下幾個階段:Lv1:“實(shí)時性” = “越快越好”,認(rèn)為用好中斷是保證實(shí)時性的關(guān)鍵;這類朋友通常最擅長的是裸機(jī)下的“前后臺系統(tǒng)”;
Lv2:“實(shí)時性” = RTOS,認(rèn)為選一個好的RTOS,或者會用RTOS就可以保證實(shí)時性;這一階段的朋友對RTOS充滿了好奇,以編寫自己的RTOS為“ 終(zhong)極(er)目標(biāo)”;
Lv3:“實(shí)時性” = 任務(wù)拆分,這一階段已經(jīng)能正確的理解實(shí)時性窗口的概念,意識到實(shí)時性并不意味著越快越好,但也認(rèn)為“在可能的情況下”“快一點(diǎn)響應(yīng)事件沒啥壞處”;這一階段的朋友可能已經(jīng)可以在裸機(jī)和RTOS之間自由的反復(fù)橫跳,無論是裸機(jī)下的狀態(tài)機(jī)還是RTOS下的線程都已了如指掌、任務(wù)間通信更是游刃有余;
Lv4:這一階段開始思考實(shí)時性模型的特點(diǎn),并逐漸意識到模型本身其實(shí)隱含了足以顛覆過往所有關(guān)于實(shí)時性認(rèn)知的秘密;到達(dá)這一階段的朋友通常覺得沒必要、也沒心思繼續(xù)思考實(shí)時性更本質(zhì)的數(shù)學(xué)意義——因?yàn)榇藭r獲得的結(jié)論已經(jīng)足夠了應(yīng)付幾乎所有的工程開發(fā)了。順便說一下,我就在這里
。Lv5:到了這個階段,不僅腦洞大開、戰(zhàn)斗力驚人、估計打針也沒法阻止你抓破脖子了吧


——以上只是暴露年齡的玩笑,但肯定可以水幾篇SCI論文了……


【擊碎 “唯快不破” 的神話】
基于物理世界客觀法則的限制,很多應(yīng)用在制定需求說明的時候,從某一個事件發(fā)生的時刻計算,會規(guī)定一個死線(Dead Line),即:一旦事件發(fā)生了,如果不在這個死線之前完成整個對事件的處理,就視作失敗;
這里,從事件發(fā)生到死線這段時間長度,習(xí)慣上稱為實(shí)時性窗口。當(dāng)事件發(fā)生時,只有在死線內(nèi)任意時刻完成了對事件的處理,才能稱為實(shí)時性得到了滿足;
容易注意到,處理事件的過程也需要消耗時間——一般稱為事件處理時間;
圖1 實(shí)時性基本模型

圖2 實(shí)時性窗口內(nèi)不同時間段完成事件響應(yīng)




超級循環(huán)里有三個任務(wù)A、B和C;
void main(void){...while(1) {task_a();task_b();task_c();}}
每個任務(wù)都使用輪詢的方式在等待一個來自芯片外界的事件發(fā)生(先不考慮存在中斷的情況);
當(dāng)一個任務(wù)函數(shù)被執(zhí)行時會檢查對應(yīng)的事件是否已經(jīng)發(fā)生,如果確實(shí)已經(jīng)發(fā)生,則執(zhí)行后續(xù)的處理;反之則立即退出任務(wù)函數(shù)——釋放處理器;
A、B、C三個事件的實(shí)時性窗口分別為10ms, 6ms和4ms;處理三個事件的處理程序分別需要4ms、3ms和0.4ms。如圖3所示:
圖3 三個事件的實(shí)時性窗口和事件處理時間示意圖

需要強(qiáng)調(diào)的是,task_a()、task_b()和task_c()三個函數(shù)的策略本質(zhì)上都是一樣的——“一旦檢測到事件立即處理,絕不遲延”!
基于上述事實(shí),容易發(fā)現(xiàn):假如某一時刻,A、B、C三個函數(shù)都處于觸發(fā)狀態(tài)(等待處理的狀態(tài)),而超級循環(huán)恰巧進(jìn)入task_a()執(zhí)行——這種情況其實(shí)比想象中容易發(fā)生,比如從task_a()退出到task_c()執(zhí)行完成期間,事件A觸發(fā)了;從task_b()退出到task_c()執(zhí)行完成期間,事件B觸發(fā)了;在task_c退出()之后恰巧事件C又觸發(fā)了……此時,任務(wù)A會立即響應(yīng),消耗4ms的時間來完成事件處理;當(dāng)從task_a()函數(shù)退出時,剩余給task_b()的時間窗口只有2ms(6ms-4ms),而事件B的處理函數(shù)需要3ms——顯然事件B的實(shí)時性是無法得到保證的——當(dāng)然事件C已經(jīng)死得透透了……
圖 4 “越快處理越好” 導(dǎo)致其它任務(wù)無法滿足實(shí)時性要求


當(dāng)你使用“越快越好”策略時,你不會有額外的收益,而實(shí)際上是走了別人的路,讓人無路可走——典型的損人不利己;
當(dāng)你在別人需要的時候,在自己實(shí)時性得到保證的前提下,盡可能讓出對你沒有額外價值的靠前的時間,實(shí)際上是一種“利他主義”;
當(dāng)所有的任務(wù)都采用這種利他策略時,就變成了“人人為我,我為人人”的合作策略——這種情況下,如果數(shù)學(xué)證明整個系統(tǒng)一定存在一個方案來滿足所有任務(wù)的實(shí)時性需求,那么利他策略一定能找到這樣的解決方案。

既然單純的“越快越好”不可取,且“實(shí)時性窗口內(nèi)”越靠前的時間越有價值,是否意味著,其實(shí)“越靠后越好呢”?

每一個事件處理任務(wù)都清楚的知道“距離事件發(fā)生已經(jīng)過去了多長時間”;
為了做到“卡著上課鈴進(jìn)教室”,不到最后時刻,絕對不執(zhí)行任務(wù)處理。
根據(jù)這一算法,我們推演得到以下的尷尬情形:
圖 6 過于謙讓的后果……

不妨分析下過程:首先,task_a()執(zhí)行,在了解到距離自己的最后時刻還有6ms的實(shí)時后毅然的決定把寶貴的時間留給他人;于是,CPU來到了下一個任務(wù)函數(shù),基于類似的原因,task_b()也擺擺手……最終第一輪三個任務(wù)都決定再等一等……

如此謙讓(浪費(fèi))了3ms以后,任務(wù)B終于決定下場——在執(zhí)行了3ms任務(wù)處理后,成功的將隨后的任務(wù)C逼上了絕路……隨著A的淪陷,大型翻車現(xiàn)場成就達(dá)成……

【小結(jié)】
