楊秋虎
(昆明船舶設(shè)備試驗研究中心第5研究室,云南昆明 650051)
LabWindows/CVI是美國國家儀器公司推出的基于ANSI C的虛擬儀器開發(fā)平臺,包含了集成式開發(fā)環(huán)境、交互式編程方法、簡單直觀的圖形用戶界面設(shè)計、完善的兼容性、靈活的調(diào)試手段以及功能強(qiáng)大的函數(shù)庫,適用于測試測量、自動控制、數(shù)據(jù)通信、信號分析等領(lǐng)域[1-3]。
操作系統(tǒng)中,定義應(yīng)用程序的一次動態(tài)執(zhí)行為進(jìn)程,而線程是進(jìn)程內(nèi)部程序執(zhí)行的路徑,是進(jìn)程的一個執(zhí)行單元。即線程是可由系統(tǒng)調(diào)度的一個最簡單的代碼單元,負(fù)責(zé)執(zhí)行包含在進(jìn)程的地址空間中的程序代碼[4-6]。
在構(gòu)建大型系統(tǒng)或復(fù)雜多任務(wù)系統(tǒng)中,多任務(wù)并行執(zhí)行所帶來的系統(tǒng)開銷以及任務(wù)之間的耦合問題尤為重要,處理不好就會導(dǎo)致系統(tǒng)崩潰。在注重系統(tǒng)效率與性能之間的平衡時,恰當(dāng)?shù)厥褂枚嗑€程,使得各個任務(wù)之間可以在互不干擾的情況下順利運(yùn)行,可以大幅提高系統(tǒng)實時響應(yīng)特性。
應(yīng)用多線程應(yīng)用程序的優(yōu)勢在于充分利用了CPU的空閑時間片,可用較短的時間來響應(yīng)用戶的要求,使得進(jìn)程整體運(yùn)行效率得到較大提高。同時,同一線程下的多個線程共享同一片內(nèi)存,所以無需要額外構(gòu)建數(shù)據(jù)傳送機(jī)制,數(shù)據(jù)共享方便[7]。
LabWindows/CVI提供了完善的多線程庫來實現(xiàn)多線程編程,與Windows提供的軟件開發(fā)工具包Windows SDK threading API相比,其進(jìn)行了以下優(yōu)化:(1)利用線程池技術(shù)完成線程管理,將函數(shù)調(diào)度到獨立的線程中執(zhí)行。(2)利用線程安全隊列完成線程之間的數(shù)據(jù)傳遞,保證線程可在另一個線程向隊列中寫數(shù)據(jù)的同時讀取隊列的數(shù)據(jù)。(3)提供線程鎖機(jī)制完成全局變量的互斥使用。(4)提供了線程安全變量的數(shù)據(jù)保護(hù)方式。(5)提供了精度較高的異步定時器。
LabWindows/CVI是在輔助線程中運(yùn)行代碼,主線程從main函數(shù)開始執(zhí)行,在主線程特定位置開始輔助線程的執(zhí)行。典型的應(yīng)用界面中,主線程完成的主要任務(wù)包括創(chuàng)建、顯示和運(yùn)行控制界面,而利用輔助線程完成實時性較高的任務(wù)或操作,如實時通信,數(shù)據(jù)采集等。LabWindows/CVI提供了兩種在輔助線程中運(yùn)行代碼的高級機(jī)制,分別是異步定時器和線程池技術(shù)。線程池適用于運(yùn)行若干次執(zhí)行或不連續(xù)執(zhí)行的任務(wù),而異步定時器則適用于定期執(zhí)行的任務(wù)。
LabWindows/CVI的toolslib庫中提供了一系列的異步定時器訪問與操作函數(shù),異步定時器不同于面板上的常規(guī)定時器控件,有不同的調(diào)用方式,只能通過程序代碼中調(diào)用定時器新建函數(shù)NewAsyncTimer(void)實現(xiàn)。在主線程運(yùn)行時,為異步定時器運(yùn)行分配一個輔助線程。需要注意的是,如果使用多個異步定時器,其參數(shù)可能被其他線程所修改,導(dǎo)致程序運(yùn)行產(chǎn)生不必要的結(jié)果,所以不建議使用多個異步定時器。其次,異步定時器本質(zhì)上使用的Windows多媒體定時器來實現(xiàn)定時功能,多媒體定時器的最小分辨率在不同的電腦上可能不同,若設(shè)定值小于最小分辨率,程序運(yùn)行會出現(xiàn)不確定的結(jié)果,故而,推薦使用的分辨率不 <10 ms[8-10],若定時時間<10 ms,則需采用更高精度的硬件定時器。
通過Suspend Async Timer Callbacks(void)函數(shù)與Resume Async Timer Callbacks(void)函數(shù)實現(xiàn)所有異步定時器的掛起與恢復(fù)操作。通過設(shè)置定時器屬性函數(shù)可設(shè)置特定定時器的定時時間、啟動停止以及優(yōu)先級。異步定時器使用完畢后,應(yīng)及時釋放異步定時器以釋放占用的系統(tǒng)資源。
使用線程池技術(shù),若不使用系統(tǒng)的默認(rèn)線程池,需要在主線程調(diào)用函數(shù)CmtNewThreadPool創(chuàng)建新的線程池,獲取線程池句柄并設(shè)定線程池可執(zhí)行的最大線程數(shù),分配線程時有兩種分配方式,一種是不考慮優(yōu)先級直接分配,適合于只有單個輔助線程或線程之間不存在耦合或沖突的程序,通過調(diào)用函數(shù)CmtScheduleThread-PoolFunction實現(xiàn);對于多個線程并行執(zhí)行的程序,根據(jù)任務(wù)要求劃分線程優(yōu)先級,確保時間要求嚴(yán)格的線程及時執(zhí)行,調(diào)用函數(shù) CmtScheduleThreadPoolFunctionAdv在分配線程的同時確定線程的優(yōu)先級,并確定線程執(zhí)行起始和結(jié)束是否需要添加回調(diào)函數(shù),回調(diào)函數(shù)函數(shù)的有用之處在于可以在線程結(jié)束之后刷新主界面的相關(guān)信息,而無需在新建線程完成界面刷新,避免額外的系統(tǒng)開銷。線程的優(yōu)先級劃分為7個級別,一般情況下,要確保線程的優(yōu)先級別不高于系統(tǒng)響應(yīng)界面操作的優(yōu)先級。在線程執(zhí)行完畢后,需要及時地釋放線程。
多個線程并行執(zhí)行時,數(shù)據(jù)保護(hù)問題尤為關(guān)鍵。線程之間存在耦合時,多個線程可能都對某一變量進(jìn)行訪問,在線程執(zhí)行過程中,變量值的改變可能會影響其它線程的執(zhí)行,出現(xiàn)不可預(yù)料的后果。需要保護(hù)的變量特點是被兩個及以上線程訪問,在調(diào)試過程中,如果不注意數(shù)據(jù)保護(hù)問題,可能不會導(dǎo)致發(fā)生致命性的錯誤,但在發(fā)布版的情況下就會出現(xiàn)很多問題,所以從程序編寫之初就應(yīng)該將數(shù)據(jù)保護(hù)納入考慮。一般情況下,需要保護(hù)的數(shù)據(jù)有全局變量、靜態(tài)局部變量以及動態(tài)分配的變量和內(nèi)存。LabWindows/CVI提供了3種數(shù)據(jù)保護(hù)機(jī)制:線程鎖、線程安全變量與線程安全隊列。
線程鎖將需要保護(hù)的對象與線程鎖結(jié)合起來,需要保護(hù)的對象可以是某個變量,某一段代碼或是第3方庫函數(shù)。在每次訪問這些對象之前,必須調(diào)用CmtNewLock獲取線程鎖獲取才能運(yùn)行代碼或訪問變量,執(zhí)行完畢后調(diào)用CmtDiscardLock立即釋放線程鎖。若某線程訪問變量時線程鎖正被其他線程占用,則該線程需等待其他線程釋放線程鎖之后才能訪問該變量。這種方法適用于需要保護(hù)變量不多的情況,當(dāng)有多個線程鎖存在時,要避免線程之間互相占有對方正在等待的線程鎖。這會導(dǎo)致程序死鎖、界面卡死。
線程安全變量實際上結(jié)合了線程鎖的特點,在函數(shù)宏定義中利用 DefineThreadSafeVar(datatype,Varname)創(chuàng)建線程安全變量,并且只能通過如下與之匹配的線程安全變量操作函數(shù)對其進(jìn)行特定訪問(VarName代表實際變量名,datatype代表變量的具體類型,可以是基本類型變量,也可以是數(shù)組,結(jié)構(gòu)體等):
int InitializeVarName(void);//初始化
void UninitializeVarName(void);//卸載
datatype*GetPointerToVarName(void);//獲取指針
void ReleasePointerToVarName(void);//釋放指針
void SetVarName(datatype val);//設(shè)置變量值
datatype GetVarName(void);//獲取變量值
線程安全變量程序運(yùn)行之前必須調(diào)用初始化函數(shù)進(jìn)行初始化,運(yùn)行結(jié)束后要及時進(jìn)行卸載。訪問或設(shè)置變量可以采用指針或調(diào)用相關(guān)函數(shù)的方式完成,調(diào)用指針完成變量訪問之后需要及時釋放指針。
線程安全隊列,可在線程之間快速安全地傳輸數(shù)據(jù),特別適用于一個線程不斷向隊列寫數(shù)據(jù),另一個線程不斷讀取的情況,可避免對數(shù)據(jù)同時讀寫發(fā)生沖突,例如數(shù)據(jù)采集、實時通信等高速讀寫的任務(wù)。通常輔助線程負(fù)責(zé)讀取數(shù)據(jù)或獲取實時信息,主線程讀取數(shù)據(jù)進(jìn)行分析并顯示。
在編寫某儀器自動控制軟件過程中,充分利用了多線程技術(shù)。按照軟件需求,將需要處理的任務(wù)劃分為界面響應(yīng)、實時通信、數(shù)據(jù)顯示及數(shù)據(jù)分析。所有數(shù)據(jù)都是通過RS485通信方式,由網(wǎng)絡(luò)內(nèi)各從站通過總線發(fā)送到上位機(jī)。根據(jù)具體的任務(wù)要求將各任務(wù)分配到各線程中執(zhí)行,將界面響應(yīng)作為主線程,實時通信、數(shù)據(jù)顯示和數(shù)據(jù)分析作為輔助線程,在并發(fā)的輔助線程中,考慮到實時通信對系統(tǒng)的重要性,將實時通信線程的優(yōu)先級設(shè)為最高,僅次于主線程,由于存在通訊數(shù)據(jù)的寫入與讀取會同時發(fā)生的情況,所以對于通訊數(shù)據(jù)采用線程安全隊列技術(shù),避免讀寫同時進(jìn)行時發(fā)生沖突,各線程具體實現(xiàn)方法可以是線程池技術(shù),也可是異步定時器。
界面具有自動控制系統(tǒng)的基本參數(shù)設(shè)置信息、操作按鈕、實時運(yùn)行狀態(tài)顯示等功能。界面響應(yīng)線程作為主線程,需及時響應(yīng)各種消息,并對操作人員的操作出快速響應(yīng)。
該線程在系統(tǒng)開始運(yùn)行后自動運(yùn)行,負(fù)責(zé)與3個從站不斷進(jìn)行通信,獲取從站的運(yùn)行信息,由于采用請求/應(yīng)答通訊方式,各從站只在主站發(fā)出請求信息時回復(fù)主站的查詢或控制信息,故而采用輪詢的方式對各子站進(jìn)行查詢。
實時通信線程中的通信信息既包含從站對主站的響應(yīng)信息,也包含主站對從站的控制信息。響應(yīng)信息中包含了各子站的運(yùn)行狀態(tài)信息,這些信息存在同時被數(shù)據(jù)分析線程和實時通信線程訪問的可能性,這些數(shù)據(jù)需要考慮數(shù)據(jù)保護(hù)。考慮到通訊的數(shù)據(jù)量較大,故新建一個線程安全隊列,實時通信線程每次接收到合法信息之后,都寫入線程安全隊列中,寫入完畢之后觸發(fā)線程安全隊列回調(diào)函數(shù)完成數(shù)據(jù)分析。通信線程負(fù)責(zé)寫數(shù)據(jù)進(jìn)線程安全隊列,數(shù)據(jù)分析線程用于從線程安全隊列中讀取數(shù)據(jù),則兩個線程之間不會因同時訪問數(shù)據(jù)發(fā)生沖突。
對接收到的數(shù)據(jù)通常需要進(jìn)行及時顯示,這些數(shù)據(jù)代表了系統(tǒng)的實時運(yùn)行狀態(tài)和各從站的運(yùn)行信息,實現(xiàn)的方法有兩種,可與通信線程類似采用線程池技術(shù),讀取線程安全隊列內(nèi)的數(shù)據(jù),作相應(yīng)的分析處理后在界面上進(jìn)行實時顯示。也可利用異步定時器定時刷新界面上顯示控件的信息。
數(shù)據(jù)分析線程對接收到的每個子站的運(yùn)行信息進(jìn)行分析處理,如信號處理和曲線擬合等,采用線程池技術(shù)新建數(shù)據(jù)分析線程實現(xiàn)。
系統(tǒng)運(yùn)行過程中,由于主線程處于最高優(yōu)先級,所以當(dāng)主線程響應(yīng)用戶界面消息時,會導(dǎo)致實時通信線程、數(shù)據(jù)顯示線程以及數(shù)據(jù)分析線程暫時掛起,優(yōu)先響應(yīng)界面消息,界面響應(yīng)執(zhí)行完畢后,繼續(xù)執(zhí)行掛起的線程。這種處理方法的好處在于,可以并發(fā)地執(zhí)行多個任務(wù)且不發(fā)生沖突,最大效率地利用了系統(tǒng)資源。
系統(tǒng)運(yùn)行的界面如圖1所示,通過控制按鈕可完成從站的操作,如閥門開啟或關(guān)閉,電機(jī)速度設(shè)置與啟??刂频?,界面上的顯示框?qū)崟r顯示從站的運(yùn)行信息。試驗驗證采用同樣的界面進(jìn)行,分別不采用多線程技術(shù)和采用多線程技術(shù)兩種方式來實現(xiàn)界面功能。由于系統(tǒng)運(yùn)行時并無直觀數(shù)據(jù)反映兩種方式的差別,所以對試驗結(jié)果的描述只進(jìn)行定性描述。經(jīng)過多次試驗驗證,采用多線程技術(shù)時各組件的控制與界面實時操作均能及時完成,當(dāng)用戶界面顯示信息不斷刷新時,通過點擊界面上的控制按鈕,可以較好地控制各子站的動作狀態(tài),并未發(fā)生沖突或是不響應(yīng)、界面卡死的現(xiàn)象。而未采用多線程技術(shù)的方式,多個任務(wù)之間不能協(xié)調(diào)進(jìn)行,系統(tǒng)長時間處于響應(yīng)系統(tǒng)通信任務(wù)或界面刷新任務(wù)的狀態(tài),對界面操作響應(yīng)延遲或基本不響應(yīng)或是出現(xiàn)卡死現(xiàn)象,嚴(yán)重制約了系統(tǒng)的實時性要求。
圖1 系統(tǒng)運(yùn)行界面
在單任務(wù)系統(tǒng)中,多線程技術(shù)的優(yōu)點不明顯,而在多任務(wù)并行的系統(tǒng)中,多線程技術(shù)具有較大優(yōu)勢,對于單核系統(tǒng),通過將線程分配到離散的時間片上執(zhí)行,對于多核系統(tǒng),將線程分配給不同的CPU執(zhí)行,可以最大限度地利用系統(tǒng)資源,完成并行任務(wù)的執(zhí)行而不發(fā)生阻塞。LabWindows/CVI作為虛擬儀器軟件,首先在界面開發(fā)上大幅縮短了時間,采用多線程技術(shù)后,使其在自動控制領(lǐng)域的優(yōu)點得以凸顯。
[1]王建新.LabWindows/虛擬儀器高級應(yīng)用[M].北京:化學(xué)工業(yè)出版社,2013.
[2]王建新,隋美麗.LabWindows/CVI虛擬儀器測試技術(shù)及工程應(yīng)用[M].北京:化學(xué)工業(yè)出版社,2011.
[3]National Instrument Corp.LabWindows/CVI programmer reference manual [M].Dex USA:National Instrument Corp,2001.
[4]楊東升,王高峰.多線程技術(shù)在虛擬儀器開發(fā)軟件Lab-Windows/CVI的實現(xiàn)[J].電測與儀表,2005(3):39-41.
[5]李敏智.基于LabWindows/CVI的數(shù)據(jù)采集與監(jiān)控系統(tǒng)的設(shè)計與實現(xiàn)[D].武漢:武漢理工大學(xué),2009.
[6]NI Conpration.LabWindowsTM/CVI中的多線程技術(shù)[EB/OL].(2008 -01 -17)[2014 -06 -11]http://www.ni.com/white - paper.
[7]陳矯陽,陳楸,劉桓龍.基于LabWindows/CVI多線程數(shù)據(jù)采集的研究[J].科學(xué)技術(shù)與工程,2008,8(9):2459 -2461.
[8]周兵,江加和.基于LabWindows/CVI的虛擬測試平臺研究與開發(fā)[J].研究與開發(fā),2007(11):30-32.
[9]袁大偉.基于LabWindows/CVI的虛擬儀器系統(tǒng)的設(shè)計[D].哈爾濱:哈爾濱工程大學(xué),2010.
[10]裴曉梅.基于LabWindows/CVI的渦流檢測虛擬儀器系統(tǒng)的研究[D].西安:西安理工大學(xué),2003.