閆雪麗 薛 靜 王 洋 楊 彬
北京航天自動控制研究所,北京100854
地面測發(fā)控系統(tǒng)是流程的測試、發(fā)射及控制的核心,一般由主控軟件、數(shù)據(jù)處理軟件及顯示軟件等多個應(yīng)用軟件組成,實(shí)現(xiàn)發(fā)射控制流程數(shù)據(jù)的接收、判讀、顯示、處理、存儲和發(fā)送,完成啟動飛行控制軟件前的發(fā)射準(zhǔn)備工作。
近年來,航天任務(wù)呈現(xiàn)高密度發(fā)射狀態(tài),對測發(fā)控系統(tǒng)功能要求越來越高,其研制周期也在縮短,提高軟件研制效率,可復(fù)用性、可維護(hù)性等非功能性要求被提上日程。設(shè)計模式是對面向?qū)ο筌浖O(shè)計經(jīng)驗的總結(jié),是更加方便快捷地復(fù)用成功的設(shè)計思想。工程實(shí)踐表明將設(shè)計模式應(yīng)用在航天軟件設(shè)計中,可以降低軟件設(shè)計復(fù)雜程度,提高軟件可靠性[1]。
設(shè)計模式概念由Christopher Alexander提出,核心是提供一個相關(guān)問題的解決方案,使人們避免不必要的重復(fù)勞動。這個思想也可以應(yīng)用在面向?qū)ο蟪绦蛟O(shè)計領(lǐng)域,設(shè)計模式是解決某類特定的面向?qū)ο筌浖栴}的方法,也是對軟件設(shè)計人員經(jīng)驗的總結(jié)。開發(fā)人員利用設(shè)計模式可以更加簡單方便地復(fù)用成功的設(shè)計和體系結(jié)構(gòu)[2]。將已證實(shí)的技術(shù)表達(dá)成設(shè)計模式也會使新系統(tǒng)開發(fā)者更加容易理解其設(shè)計思路,使軟件系統(tǒng)易復(fù)用、易維護(hù)。
單件模式(Singleton)是一種對象創(chuàng)建型設(shè)計模式,它的意圖是保證一個類僅有一個實(shí)例,并提供一個訪問它的全局訪問點(diǎn)。為保證實(shí)例唯一性,需要從2個點(diǎn)出發(fā):
1)創(chuàng)建實(shí)例時,有創(chuàng)建檢查,保證實(shí)例唯一。
定義一個靜態(tài)成員變量_instance,初始化為0,用于記錄是否創(chuàng)建實(shí)例。如果其值為0則用唯一實(shí)例初始化它,否則返回該變量值。
2)創(chuàng)建方式唯一,保證只有一個創(chuàng)建接口。
創(chuàng)建實(shí)例的唯一接口為public類型的靜態(tài)成員函數(shù)。構(gòu)造函數(shù)聲明為protected類型,直接實(shí)例化將得到一個編譯錯誤信息。這就保證了僅有一個實(shí)例可以被創(chuàng)建。
單件模式的C++實(shí)現(xiàn)方法見圖1。
圖1 單件模式的C++實(shí)現(xiàn)方法
1)主控軟件的功能
主控軟件是地面測發(fā)控系統(tǒng)實(shí)現(xiàn)流程控制與數(shù)據(jù)判讀自動化的核心,以主機(jī)狀態(tài)和副機(jī)狀態(tài)運(yùn)行于主控計算機(jī)甲機(jī)和乙機(jī)上,在需要時,可以實(shí)現(xiàn)主副機(jī)切換。同時,主控軟件啟動后在數(shù)據(jù)庫中記錄測試項信息、發(fā)送/接收數(shù)據(jù)、出錯信息及用戶操作等數(shù)據(jù),便于后期判讀和排故[3]。
2)出現(xiàn)問題的操作及現(xiàn)象
執(zhí)行測試流程過程中,用戶在主控軟件上操作,使主機(jī)切換為副機(jī),再切換為主機(jī),點(diǎn)擊“啟動測試”按鈕執(zhí)行流程。在執(zhí)行幾個(每次數(shù)量不同)測試步序時,主控界面上有提示框“存儲測試數(shù)據(jù)失敗”,主控軟件異常終止。
3)產(chǎn)生問題的原因
經(jīng)分析和排查發(fā)現(xiàn),存入數(shù)據(jù)庫緩沖區(qū)的各項數(shù)據(jù),分別以結(jié)構(gòu)體方式定義,每個結(jié)構(gòu)體的成員變量數(shù)量和類型各有不同。寫文件線程首先判斷緩沖區(qū)內(nèi)容的數(shù)據(jù)類型bType,按照對應(yīng)的結(jié)構(gòu)體成員變量的數(shù)量和類型存儲到數(shù)據(jù)庫文件中,并清除緩沖區(qū)內(nèi)容。
在“啟動測試”按鈕的響應(yīng)函數(shù)中,創(chuàng)建一個寫文件線程和一個mdb存儲文件。在主機(jī)切換為副機(jī)時沒有關(guān)閉這個線程,再切換為主機(jī)后,由于用戶操作需要又一次點(diǎn)擊“啟動測試”按鈕,其響應(yīng)函數(shù)再次創(chuàng)建一個寫文件線程和一個mdb存儲文件。為方便描述,這2個線程分別稱為線程1和2。
當(dāng)線程1和2都獲得了bType,線程1在存儲數(shù)據(jù)前被線程2中斷。線程2讀取數(shù)據(jù)后刪除該數(shù)據(jù)。回到線程1的中斷點(diǎn),線程1繼續(xù)執(zhí)行。若線程1要取的數(shù)據(jù)類型與緩沖區(qū)現(xiàn)在存放的一致,則程序會繼續(xù)執(zhí)行,只是線程1少存了一組數(shù)據(jù)。若線程1要取的數(shù)據(jù)類型與緩沖區(qū)現(xiàn)在存放的不一致,那么線程1讀數(shù)時,造成內(nèi)存訪問越界,程序被異常終止(這也是復(fù)現(xiàn)問題過程中,造成軟件異常退出時,執(zhí)行測試步序數(shù)量不同的原因)。主控軟件從開始測試到異常終止的過程見圖2。
3.1 打補(bǔ)丁法
該問題出現(xiàn)源于讀取和修改數(shù)據(jù)庫緩沖區(qū)的類是可以創(chuàng)建多個寫文件線程的,解決方法是保證只有一個寫文件線程訪問數(shù)據(jù)庫的緩沖區(qū)。最直接的解決方法是及時關(guān)閉靈活創(chuàng)建的線程,在主機(jī)切換為副機(jī)后,銷毀寫文件線程、關(guān)閉存儲文件并斷開與數(shù)據(jù)庫的連接。在副機(jī)切換為主機(jī)后,再重新創(chuàng)建寫文件線程、創(chuàng)建存儲文件,建立與數(shù)據(jù)庫的連接。
圖2 主控軟件問題出現(xiàn)的過程圖
該種方法雖然簡單直接,但屬于發(fā)現(xiàn)問題后打補(bǔ)丁的解決辦法。設(shè)計初期,需要設(shè)計人員準(zhǔn)確且全面地分解用戶操作和軟件運(yùn)行剖面才能做此設(shè)計,因此對軟件設(shè)計人員的要求高,且代碼重用性差。
3.2 單件模式方法
3.2.1 設(shè)計思想
程序設(shè)計中應(yīng)避免創(chuàng)建線程的隨意性,我們期望在主控軟件運(yùn)行時,從始至終有且只有一個寫文件線程來訪問數(shù)據(jù)庫。當(dāng)主控軟件以主機(jī)狀態(tài)運(yùn)行時,該線程處于運(yùn)行狀態(tài);當(dāng)主控軟件以副機(jī)狀態(tài)運(yùn)行時,該線程處于掛起狀態(tài)。該線程的創(chuàng)建,應(yīng)置于程序啟動后就會立即執(zhí)行且只能執(zhí)行一次的函數(shù)中。
設(shè)計時,考慮代碼結(jié)構(gòu)和后期維護(hù),將寫文件線程的維護(hù)和數(shù)據(jù)庫的操作分離開來,我們需要新建一個數(shù)據(jù)庫操作類CAdoCommand變量,用于對數(shù)據(jù)庫進(jìn)行訪問和操作。當(dāng)主機(jī)切換為副機(jī)時,只需要關(guān)閉主機(jī)軟件與數(shù)據(jù)庫的連接,關(guān)閉存儲文件;當(dāng)切換為主機(jī)時,建立與數(shù)據(jù)庫的連接,新建存儲文件。
3.2.2 實(shí)現(xiàn)方法
利用單件模式的一個類只有一個實(shí)例的特性實(shí)現(xiàn):
1)用將數(shù)據(jù)記錄類CDataRecoder的靜態(tài)成員函數(shù)Instance來定義這個類操作,定義一個靜態(tài)成員變量_instance,它是指向類的唯一實(shí)例指針,其構(gòu)造函數(shù)聲明為protected,這就保證了僅有一個實(shí)例可以被創(chuàng)建。在CDataRecoder構(gòu)造函數(shù)中創(chuàng)建寫文件線程,試圖直接實(shí)例化CDataRecoder對象將在編譯時得到一個報錯信息;
2)主控軟件啟動后就只有一個主窗口運(yùn)行,將創(chuàng)建CDataRecoder對象綁定在主窗口構(gòu)造函數(shù)CCentralConsoleDlg中,從而保證只有一個CDataRecoder實(shí)例;
3)在CDataRecoder類中增加成員變量CAdoCommand m_adoCmd,用于數(shù)據(jù)庫的連接、斷開操作。
針對主控軟件問題的單件模式具體實(shí)現(xiàn)方法見圖3,其中紅色部分是修改部分。
3.2.3 單件模式的優(yōu)勢
單件模式有2個特性:唯一實(shí)例和一個全局訪問點(diǎn)。單件模式應(yīng)用在主控軟件上,有以下幾點(diǎn)優(yōu)勢:
圖3 單件模式的實(shí)現(xiàn)方法
1)從一個類只有一個實(shí)例的角度看:
①提高軟件可靠性
多線程訪問資源沖突等問題在主控軟件運(yùn)行中時有發(fā)生,此類問題難發(fā)現(xiàn)、難排查且難測試,只有在實(shí)際運(yùn)行到觸發(fā)點(diǎn)時才能表現(xiàn)出來。采用單件模式設(shè)計主控軟件,可從設(shè)計早期就避免建立多個相同線程、同一資源被多處使用等情況,可以提高軟件可靠性;
②代碼結(jié)構(gòu)清晰
使用單件模式來保證類只能創(chuàng)建唯一實(shí)例,不需要考慮在不同輸入條件時軟件運(yùn)行剖面,無須多處增加代碼保證唯一實(shí)例。相比方法1在主機(jī)切換為副機(jī)后增加代碼關(guān)閉線程,單件模式使代碼結(jié)構(gòu)更加清晰。結(jié)構(gòu)清晰的代碼框架或代碼,更容易實(shí)現(xiàn)重用;
③封裝性好
在構(gòu)造函數(shù)中創(chuàng)建寫文件線程,可以保證只有一個線程創(chuàng)建,避免創(chuàng)建線程的隨意性,封裝性好;
④易管理易維護(hù)
該線程在切換主副機(jī)時一直存在,無需重復(fù)關(guān)閉和創(chuàng)建,便于管理。采用單件模式,可以降低開發(fā)人員的分析設(shè)計工作量和難度,降低了對設(shè)計人員的要求,更容易維護(hù)。
2)從提供一個全局訪問點(diǎn)的角度看:
①數(shù)據(jù)共享
若一個模塊中定義了數(shù)據(jù)庫接口實(shí)例,而其它模塊也需要訪問該數(shù)據(jù)庫的數(shù)據(jù),則又需要重新定義數(shù)據(jù)庫接口實(shí)例,這樣在內(nèi)存中就保存了多份同樣的數(shù)據(jù),降低了內(nèi)存利用效率。若使用單件模式,只保留一個數(shù)據(jù)庫接口實(shí)例,提供一個全局訪問點(diǎn),各個模塊就可以共享數(shù)據(jù),減少資源開銷,提高軟件運(yùn)行效率;
②維護(hù)名空間
單件模式提供一個全局訪問點(diǎn),是對全局變量的一種改進(jìn),避免了存儲唯一實(shí)例的全局變量污染名空間,便于管理和后期維護(hù)。
4.1 重用框架的改進(jìn)方案
近年來,地面測發(fā)控系統(tǒng)軟件產(chǎn)品復(fù)雜度不斷增加,為提高軟件產(chǎn)品的可復(fù)用性、可維護(hù)性和可靠性,降低對設(shè)計人員的要求,地面主控軟件復(fù)用框架的研制也被提上日程[4]。從資源管理角度看,主控軟件的某些資源由使用對象進(jìn)行抽象,但并非能夠創(chuàng)建任意數(shù)量的實(shí)例,比如界面上彈出的紅色報錯對話框。按照任務(wù)要求,同一時間只能出現(xiàn)一個紅色報錯對話框,用來顯示各個設(shè)備異常的報錯信息。雖然該對話框?qū)嵗怯筛鱾€設(shè)備控制器進(jìn)行抽象的,但不能創(chuàng)建任意數(shù)量的報錯對話框。此時,可以采用單件設(shè)計模式Singleton。它的本質(zhì)是為了確保應(yīng)用程序在使用環(huán)境中僅有一個實(shí)例占據(jù)資源,避免產(chǎn)生多實(shí)例的資源競爭問題。此處的“資源”不只是狹義的內(nèi)存數(shù)據(jù)區(qū)、消息隊列緩沖區(qū)的數(shù)據(jù),還包括依據(jù)任務(wù)要求主控軟件只能出現(xiàn)的一個實(shí)例,比如對話框、運(yùn)行狀態(tài)等。
單件模式是最常用的創(chuàng)建型設(shè)計模式,它的應(yīng)用可以讓設(shè)計人員更加方便地復(fù)用成功的設(shè)計和體系結(jié)構(gòu)。單件模式的實(shí)現(xiàn)通常由單件狀態(tài)標(biāo)記SS、單件獲取接口SI和單件資源句柄SH構(gòu)成。初始化時置SS為空,程序運(yùn)行過程中調(diào)用SI獲取SH,并通過SH使用單件資源。在SI工作時,首先檢查SS的值是否為空,如果為空則創(chuàng)建單件資源并綁定這些資源到SH上,置SS的值為滿并返回SH;若SS不為空則標(biāo)志著單件資源已創(chuàng)建,應(yīng)立即返回SH。單件模式的模型如圖4所示。
圖4 單件模式的模型
4.2 紅色報錯對話框的設(shè)計方法
1)設(shè)計要求:在主控軟件界面上,保證在同一時刻只有一個紅色報錯對話框,能夠顯示各個外圍設(shè)備的異常信息。
2)實(shí)現(xiàn)方法:
使用單件模式為界面顯示類創(chuàng)建唯一的實(shí)例,在任何一個訪問點(diǎn)訪問類實(shí)例,調(diào)用界面顯示類的方法,完成界面顯示功能。分解設(shè)計要求與單件模式特性的對應(yīng)關(guān)系:
①鎖定資源:紅色對話框的控制權(quán);
②SS:對話框的句柄;
③SH:顯示控制器的異常信息;
④SI:對話框句柄為空,則創(chuàng)建一個紅色對話框,否則指向當(dāng)前句柄。在這個全局訪問點(diǎn),控制器填入顯示信息。
4.3 主機(jī)狀態(tài)的設(shè)計方法
1)設(shè)計要求:在主控計算機(jī)的甲乙上以主機(jī)和副機(jī)狀態(tài)運(yùn)行主控軟件,需要保證只能有一個主控程序以主機(jī)狀態(tài)運(yùn)行。
2)實(shí)現(xiàn)方法:使用單件模式保證測發(fā)控流程控制權(quán)只有一個實(shí)例。
①鎖定資源:測發(fā)控流程的控制權(quán);
②SS:操作系統(tǒng)級的命名互斥量;
③SH:構(gòu)造函數(shù)中使用CreateMutex創(chuàng)建同名互斥量;
④SI:若創(chuàng)建成功,則當(dāng)前主控程序合法取得流程控制權(quán),可繼續(xù)運(yùn)行;若創(chuàng)建失敗,則意味著流程控制權(quán)被其他主控程序鎖定,當(dāng)前程序應(yīng)當(dāng)立即退出主機(jī)狀態(tài)。
4.4 設(shè)備控制的設(shè)計方法
1)設(shè)計要求:對外部設(shè)備進(jìn)行發(fā)送命令、接收數(shù)據(jù)等操作時,主控軟件首先要檢查設(shè)備是否連接正常。若未連接則提供重連接口,若已連接則關(guān)閉重連接口,保證連接的唯一性和存在性。
2)實(shí)現(xiàn)方法:
①鎖定資源:特定測試設(shè)備的控制權(quán);
②SS:用設(shè)備編號和操作句柄創(chuàng)建設(shè)備映射表;
③SI:在使用該設(shè)備前,檢查相應(yīng)設(shè)備編號是否存在操作句柄;
④SH:若存在操作句柄,則使用該操作句柄控制設(shè)備;若不存在操作句柄,則對遠(yuǎn)端設(shè)備進(jìn)行初始化操作,初始化成功后將新創(chuàng)建的操作句柄加入該設(shè)備的映射表項中,并返回新創(chuàng)建的操作句柄。
闡述了某主控軟件的資源訪問沖突問題,采用2種方法解決該問題,并總結(jié)出單件模式解決問題的優(yōu)勢。從報錯對話框、主機(jī)狀態(tài)和設(shè)備控制等3個方面的設(shè)計方法描述單件模式的實(shí)現(xiàn)方法,將單件模式應(yīng)用在主控重用框架上,可以使代碼結(jié)構(gòu)更加清晰易懂,提高軟件的可維護(hù)性、可復(fù)用性。
[1] 楊喆,馬衛(wèi)華,等.設(shè)計模式在地面測發(fā)控軟件中的應(yīng)用[J].航天控制,2014,32(2):91-95.(Yang Zhe, Ma Weihua, et al. Design Pattern Used in Software Reuse of Test Launch and Control System[J]. Aerospace Control, 2014,32(2):91-95.)
[2] Gamma E,Helm R,Johnson R.可復(fù)用面向?qū)ο筌浖幕A(chǔ)[M].李英軍,譯.北京:機(jī)械工業(yè)出版社,2000.(Gamma E,Helm R,Johnson R. Design Patterns:Elements of Reusable Object-Oriented Software[M].Li Yingjun,Translate.Beijing:China Machine Press,2000.)
[3] 夏克寒,牟建華,等.導(dǎo)彈測試流程優(yōu)化系統(tǒng)設(shè)計與實(shí)現(xiàn)[J].導(dǎo)彈與航天運(yùn)載技術(shù), 2012, 318(2):43-46. (Xia Kehan, Mou Jianhua,et al. Design and Implementation of Missile Test Process Optimizing System[J]. Missiles and Space Vehicles, 2012,318(2):43-46).
[4] Fayad M, Schmidt D, Johnson R. Building Application Frameworks: Object-Oriented Foundations of Framework Design[M]. New York: John Wiley&Sons, 1999.