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