自從用上緩沖,通信不再破功
元朝末年,黃河泛濫,瘟疫流行,加之官僚腐敗,漸至于民不聊生,老百姓為了活命只得揭竿而起。一時間,風(fēng)云變幻,狼煙四起。在一眾草莽英雄中,朱元璋采納謀士朱升的九字真言:“深挖洞、廣積糧、緩稱王”,韜光養(yǎng)晦,積蓄力量,最終定鼎天下,平定四方。
本文引用地址:http://m.butianyuan.cn/article/202005/412945.htm再后來,中蘇交惡時期,毛主席也振聾發(fā)聵地提出“深挖洞、廣積糧、不稱霸”的號召。
兩朝太祖都是百年一遇的政治家、軍事家,英雄所見略同,他們深知戰(zhàn)略儲備的力量,曉得唯有建設(shè)深厚的國家儲備,才不至于陣亡于暗暗長夜而等不來那終將來臨的天光。
就拿現(xiàn)在來說吧,我輩吃瓜群眾有福氣,可以好整以暇地看美國各個州的州長和特朗普在推特上罵來罵去地打嘴炮,其實這還不是因為美國聯(lián)邦政府儲備的醫(yī)療物資消耗殆盡,沒有應(yīng)急的儲備造成的?
這些儲備平時躺在倉庫里睡大覺,還要付出長期維護和定期更換的高昂成本,但是它們在關(guān)鍵時刻能救命,疫情連三月,呼吸機抵萬金吶!當(dāng)需求高峰期來時,這些平時沒啥用的儲備可以贏得寶貴的時間,挽救脆弱的生命!
不過,立國不到三百年的美國人哪有這種歷史感悟?
通過建立“空間”縱深,以應(yīng)對時間密集型的突發(fā)需求,拿空間換時間,這就是“儲備”的意義。
在程序員的世界里,這種儲備叫做“緩沖”。今天,筆者就跟大家分享一個多年前發(fā)生在自己身上的案例,一個因為沒有使用儲備導(dǎo)致“數(shù)據(jù)丟失”的故事。
一
那正是天寒地凍的時節(jié)。
窗外狂風(fēng)席卷,人影難覓,只有一面冷颼颼的月亮像瑤臺的鏡子,遠遠地掛在云端。那天,甚是高遠,似穹廬,籠蓋在一座小樓的上方。
那樓里只亮著一盞燈,亮燈的房間里只有一個人。
天高云淡,這個房間很孤單,這個人也很孤單。
這個人,就是在下!
月黑風(fēng)高夜,正是捉蟲時,沒錯,別看在下枯坐已久,但腦袋卻在轉(zhuǎn)個不停,在下正在對著電腦屏幕找bug!
當(dāng)時,項目組正在做一款藍牙娛樂設(shè)備,概而言之,這款設(shè)備插上U盤能放歌,接上藍牙能免提,連上手機還能用音頻流播放手機里的音樂。
現(xiàn)在說來這些都不算啥,但是在十余年前,那可算是個新概念。
這個設(shè)備的開發(fā)采用了雙處理器方案,概而言之,一顆主控處理器處理人機接口,主要功能是以按鍵和顯示屏的方式管理播放列表、通話和音樂播放,還有一顆藍牙單芯片處理和手機的藍牙通信,主要功能是把來電請求、通話狀態(tài)發(fā)給主控處理器,同時接收來自主控的接聽/掛斷電話指令、音樂控制指令等。
主控處理器是個32位的單片機,藍牙芯片選用CSR集成了藍牙基帶的單芯片,兩者通過SCI接口進行通信。
在下不才,在里面負(fù)責(zé)藍牙單芯片的開發(fā)。
二
如前所述,這兩顆單片機以SCI接口進行通信。為了更順口一些,還是說串口吧,只不過,大多數(shù)人印象中的串口是RS232,它主要用于設(shè)備間的通信,而筆者這里是同一個設(shè)備電路中的通信,沒有走RS232電平,直接走TTL電平。
有串口通信就有通信協(xié)議,為了減輕主控開發(fā)人員的負(fù)擔(dān),在下自告奮勇地承擔(dān)了協(xié)議的制定工作,卻不成想,這倒成了我后來“背鍋”的原因。
剛開始,我和負(fù)責(zé)主控芯片軟件開發(fā)的李工一邊喝著茶水磨牙拌嘴,一邊“你打你的,我打我的”地加班加點,偶有串口聯(lián)調(diào)通信,也是一切順利,萬事大吉,直到突如其來的數(shù)據(jù)丟失把這種歲月靜好打成了滿地狼藉。
那是將要起風(fēng)的一天傍晚,同事們都各自歸家,游戲人間煙火去了,獨獨剩下我和李工還在苦逼地寫代碼。
北島說:如果你是一條船,漂泊就是你的命運,可別靠岸。領(lǐng)導(dǎo)說:如果你是一個工程師,加班就是你的命運,可別想著早下班。
想著那些早下班的同事,我也想到一句話:哪里有什么歲月靜好,只不過我和李工在替你們負(fù)重前行!
辦公室里萬籟俱靜,靜的有些出奇,李工在一旁眉頭緊鎖,間或捏著下巴頦子向我投來深情的一瞥,直讓人起雞皮疙瘩。我在一旁也打起了嘀咕,“這廝有事?”
果然,李工帶著斟酌的語氣開口了,“天雷君,你定的串口通信協(xié)議莫不是有問題?感覺丟數(shù)據(jù)呢!”
原來,從今天下午起,李工做通話管理那部分程序時,有時候得不到正確順序的數(shù)據(jù)。比方說,手機來電話了,用戶直接在手機上接通了,藍牙芯片這邊本來會按順序發(fā)過來“來電請求、接通等待、接通通話”,可是有的時候,沒有“來電請求”就直接把“接通等待”這個報文發(fā)過來了。
而通話管理程序?qū)嶋H上是一個狀態(tài)機,按照這幾條報文跳轉(zhuǎn)通話狀態(tài),現(xiàn)在報文次序不對,狀態(tài)機自然就亂套了。
問題是顯然的,原因似乎也是呼之欲出的。按李工的說法,是藍牙鏈路的射頻通信干擾了串口通信,導(dǎo)致報文里的數(shù)據(jù)出錯,按照李工的提議,應(yīng)該修改串口通信協(xié)議,每條報文應(yīng)該連發(fā)兩次,這樣才能保證出錯的幾率大大降低。
那時我還年輕,慣于把別人甩的鍋自覺地戴在自己頭上。于是,我默默地收起內(nèi)心的驕傲,采納了他的意見。
不曾想,待我把報文發(fā)送改成連發(fā)兩次后,問題出現(xiàn)的幾率似乎更高了?。?/span>
于是,李工給我判了刑,要求大改通信協(xié)議,然后就拂袖回家了。
三
我嘗遍世間冷暖炎涼,但依然愿在薄情的世界里深情地活著——這才是生活。
李工走后,偌大的辦公室只剩下我一個人了。
月亮漸漸爬上樹梢,寒風(fēng)在窗外咆哮,月亮很孤單,我也很孤單。
我孤獨地看著李工留給我的代碼,在這蕭殺的寂靜里,捕捉著不知藏身何處的bug。
是的,“嚴(yán)于律人、寬以待己”的我可沒覺得自己有哪里不對,‘通信協(xié)議有什么好改的?’我一邊在鼻尖哼著氣,一邊看李工寫的代碼。
在李工的程序里,是通過中斷接收串口發(fā)送的字節(jié),然后在一個單獨的任務(wù)解析報文的,解析出一條完整的報文后,再根據(jù)報文的含義向其它相應(yīng)的任務(wù)里發(fā)消息。
我看了看李工為串口報文解析任務(wù)設(shè)定的優(yōu)先級,居然是最低的!
其實,當(dāng)時我也不知道該怎么設(shè)置任務(wù)的優(yōu)先級,但是,聯(lián)想到之前李工指控我通信協(xié)議有問題的情景,我就是覺得:怎么能夠把這么‘重要’的任務(wù)設(shè)置成最低的優(yōu)先級呢?
我一邊在鼻孔哼著氣,一邊改了任務(wù)的優(yōu)先級。三下五除二,再調(diào)試一把,還別說,果然好多了,測了好幾遍,沒問題!
既如此,我釋然了。根本不是通信協(xié)議的事兒,而是報文一股腦地發(fā)過來時,主控這邊處理報文不及時,導(dǎo)致“來電請求”報文還沒解析完時,其中的數(shù)據(jù)就被破壞了。
于是,我恍然了。任務(wù)優(yōu)先級設(shè)置不同,會導(dǎo)致這么明顯的差異,這實際上也給我敲響了警鐘:任務(wù)優(yōu)先級不要隨便動!
可是,我又再度默然了。我這么貿(mào)然地改了優(yōu)先級,是不是可能會有很多其它功能出現(xiàn)莫名其妙的故障呢?于是,我一個激靈,默默地把優(yōu)先級改了回去。
四
歲月如水,撥動著墻上的鐘表指針,也撥動著我的心弦。
看著眼前剩下的半杯水,我生起了哲學(xué)的深思:“人生,過一天少一天,可是我們并不急著把這一輩子過完;水杯,喝一口少一口,可是我們并不想著一口氣喝光。壽命、水杯都是一種緩沖型的容器,讓我們可以安步當(dāng)車,不疾不徐。”
那串口接收豈非也是如此?只要給它一個足夠的緩沖,即便短時期內(nèi)來了好幾條報文,也不妨礙我們一條一條地處理了!
開了竅的我,帶著興奮的心情,在李工的代碼里實現(xiàn)了一個環(huán)形緩沖器。拿出512個字節(jié),開個數(shù)組,建立兩個索引,分別標(biāo)記讀取位置和寫入位置,這些索引到了512后自動歸零。剛開始時,自然是寫入索引大于讀取索引,數(shù)據(jù)就這樣魚貫而入魚貫而出。
慢慢地,只要寫入索引的回零次數(shù)不大于(讀取索引回零次數(shù)+1),即使出現(xiàn)了數(shù)據(jù)堆積,只要假以時間,也能準(zhǔn)確無誤地把數(shù)據(jù)消費完。而一旦出現(xiàn)寫入索引回零次數(shù)大于讀取索引回零次數(shù)+1,就表示數(shù)據(jù)出現(xiàn)了溢出,此時調(diào)大緩沖區(qū)的大小即可。
問題就這么順利地解決了,自從用上了緩沖,后面的通信便沒有再破過功。
至于李工,他看完被我改造過的代碼,再次給我投來深情的一瞥。我回以嫣然一笑,對著他帥氣的臉龐吐出兩句詩:桃花潭水深千尺,不及我跟李工情吶!
評論