姜 悅,褚厚斌,張麗曄,蔡斐華,李 智
(中國運載火箭技術(shù)研究院,北京 100076)
隨著計算機多核處理器的迅速普及,軟件架構(gòu)已經(jīng)逐漸從傳統(tǒng)的串行模式轉(zhuǎn)變?yōu)椴⑿心J?以充分發(fā)揮多核處理器的效率和潛能。多核計算機擁有強大的處理能力,在并行應(yīng)用領(lǐng)域有著廣闊的應(yīng)用前景,多線程編程技術(shù)已成為當(dāng)前重要的軟件技術(shù)之一。
在航天運載領(lǐng)域,匹配試驗結(jié)束后,試驗數(shù)據(jù)后處理解析軟件需要將保存下來的dat 格式的遙測原碼,通過挑幀、十進制轉(zhuǎn)換、公式轉(zhuǎn)換、寫入文件等處理方法,轉(zhuǎn)換成物理量值供各系統(tǒng)進行判讀評估,并進行受控。普通的單線程數(shù)據(jù)后處理解析能夠按照幀協(xié)議的格式將遙測原碼解析,并進行文件寫入,但數(shù)據(jù)文件寫入遲滯,導(dǎo)致主線程阻塞,效率不高。如何快速、高效、可靠且準(zhǔn)確地寫入數(shù)據(jù)文件是后處理解析軟件的核心任務(wù)。
多線程是現(xiàn)代操作系統(tǒng)中非常重要的概念。多線程即允許同時執(zhí)行多個線程,對完成并行任務(wù)和提升用戶體驗非常重要。在傳統(tǒng)的操作系統(tǒng)中,進程通常指代正在運行的程序的實例,每個進程都有自己的地址空間和一個執(zhí)行線程,該線程通常叫做主線程[1]。在同一進程環(huán)境中可以執(zhí)行多個線程,一般而言,運行在同一個進程中的多個線程具有相同的地址空間。線程是進程中的實際運作單位,是操作系統(tǒng)分配處理器時間的基礎(chǔ)單元,它們彼此合作、交流,共享該進程中的全部系統(tǒng)資源,如處理器時間、內(nèi)存和變量等[2]。
多線程設(shè)計中最重要的一個環(huán)節(jié)就是識別軟件中的可并行部位,并對該部位進行問題分解,即將軟件劃分為多個獨立的任務(wù),并確定這些任務(wù)之間的相互依賴關(guān)系。
問題分解的方式主要有三種[3]:
(1)任務(wù)分解:將不同的行為分配給不同的線程,需要移除任務(wù)間的依賴性或使用復(fù)制來分離依賴性。此種方式需打破原有程序的邏輯關(guān)系,消除任務(wù)間的依賴性,適用于任務(wù)多且并行度高的問題。
(2)數(shù)據(jù)流分解:將計算分割成一系列階段,每個線程在不同的階段同時工作。此種方式不破壞原有程序的邏輯關(guān)系,適用于邏輯性強的問題,但數(shù)據(jù)流影響程序并行執(zhí)行能力,易出現(xiàn)線程空閑。
(3)數(shù)據(jù)分解:分割數(shù)據(jù)集,多個線程對不同的數(shù)據(jù)集執(zhí)行同樣的操作。此種方式不破壞原有程序的邏輯關(guān)系,適用于數(shù)據(jù)多且格式規(guī)范的問題。
試驗數(shù)據(jù)后處理解析軟件通過讀取試驗過程中存儲的遙測原碼,根據(jù)XML 文件中的協(xié)議、幀結(jié)構(gòu)、參數(shù)和公式的配置信息,完成數(shù)據(jù)的解析,并以文本形式存儲。后處理解析執(zhí)行過程如圖1 所示,包括讀取數(shù)據(jù)原碼、類型判斷、獲取主幀、幀解析、獲取子幀、公式轉(zhuǎn)換、格式處理及文件寫入7 個主要模塊。
圖1 幀數(shù)據(jù)處理過程圖Fig.1 Flow diagram of data processing
(1)讀取數(shù)據(jù)原碼
軟件首先對文件進行檢測,確認(rèn)文件格式,識別文件類型,然后逐幀讀取遙測原碼文件。
(2)類型判斷
軟件對讀取的一幀原碼幀進行幀頭識別和幀類型判斷,以確定合理的解析方式。
(3)獲取主幀
獲取主幀主要從數(shù)據(jù)流中完成整幀的提取,采用判斷幀頭和幀長度的方式獲取整幀,然后再對幀中的參數(shù)進行解析。
(4)幀解析
幀解析功能主要是根據(jù)參數(shù)的波道位置和占字節(jié)數(shù)從幀緩存區(qū)將參數(shù)存儲的十六進制數(shù)據(jù)取出,并根據(jù)數(shù)據(jù)類型轉(zhuǎn)換成十進制。
(5)獲取子幀
挑包功能應(yīng)用于主幀中有嵌入子幀(異步幀)的協(xié)議,在完成主幀解析后,繼續(xù)獲取主幀中的嵌入子幀,獲取嵌入幀采用判別幀頭、幀長度和幀尾的方式獲取整幀,對沒有幀尾的子幀,采用判別幀頭、幀長度和下一幀頭的方式獲取整幀,該種判別子幀的方式可以過濾掉半幀的情況。
(6)公式轉(zhuǎn)換
遍歷幀參數(shù)結(jié)構(gòu)中的所有參數(shù),根據(jù)參數(shù)代號從公式轉(zhuǎn)換庫中查詢該參數(shù)的物理量轉(zhuǎn)換公式,將參數(shù)的十進制數(shù)轉(zhuǎn)換為物理量值,重新存入?yún)?shù)結(jié)構(gòu)中。在完成公式轉(zhuǎn)換后,將得到由參數(shù)物理量值組成的不同解析幀。
(7)格式處理及文件寫入
在格式處理及文件寫入階段,軟件按照數(shù)據(jù)處理格式要求,對解析幀完成寫入數(shù)據(jù)的格式轉(zhuǎn)換,以及時間和物理量值的拼接,然后將結(jié)果寫入?yún)?shù)文件。
在單線程架構(gòu)下對圖1 所示的后處理過程中各模塊進行時間插樁,采集各模塊的運行時間,分析結(jié)果如圖2 所示??梢钥闯?模塊①~⑥運行的總耗時與模塊⑦運行的總耗時比例約為1 ∶13,同時考慮到模塊①~⑥邏輯關(guān)系強,并行度低,模塊⑦并行度較高,因此將關(guān)鍵因素定位為“格式處理及文件寫入”模塊,進行多線程算法設(shè)計。
圖2 單線程架構(gòu)分析圖Fig.2 Analysis of single-thread architecture
考慮到后處理解析具有邏輯性較強,數(shù)據(jù)較多且格式規(guī)范等特點,采用基于數(shù)據(jù)分解的問題分解方式,對本問題的模型適用度更高,且應(yīng)用至不同型號時無須重新進行邏輯分析,可擴展性強。因此,本設(shè)計采用基于數(shù)據(jù)分解的后處理多線程設(shè)計,即將每個解析幀結(jié)構(gòu)按CPU 核數(shù)進行分割,將分割后的數(shù)據(jù)塊分配至不同的CPU 核進行處理,如圖3 和圖4 所示。
圖3 系統(tǒng)設(shè)計框圖Fig.3 Design diagram of system
圖4 多線程后處理解析方法示意圖Fig.4 Diagram of multi-thread method for test data post-processing parsing
多線程的執(zhí)行通常存在著無序性,而試驗數(shù)據(jù)后處理解析過程對參數(shù)文件的寫入要求嚴(yán)格有序,保持原有的時間序列。因此,在任務(wù)分配時需要考慮不能有兩個及以上的線程同時向同一參數(shù)文件進行寫入操作。在任務(wù)分配方式設(shè)計時采用基于定向和閑置混合的方式,即當(dāng)分配當(dāng)前時刻的幀結(jié)構(gòu)片段時,如果上一時刻的該幀結(jié)構(gòu)片段仍在被某個線程進行處理,則采用定向分配原則;否則,采用閑置分配原則。這樣既可以保證參數(shù)寫入的準(zhǔn)確度,又可以達(dá)到各線程負(fù)載均衡。線程調(diào)度數(shù)據(jù)結(jié)構(gòu)如表1 所示。
表1 線程調(diào)度數(shù)據(jù)結(jié)構(gòu)Tab.1 Data structure of thread scheduling
具體規(guī)則為:
(1)識別跨包參數(shù):如果同一個參數(shù)出現(xiàn)在不同包幀協(xié)議中,應(yīng)予以識別并標(biāo)識,不能采用多線程方式解析;
按參數(shù)個數(shù)將一幀解析幀(解析幀數(shù)據(jù)結(jié)構(gòu)如表2 所示)拆分為獨立的等長度的幀結(jié)構(gòu)片段,分配給不同核上的線程,每個線程處理不同的幀結(jié)構(gòu)片段,能夠達(dá)到將多線程負(fù)載盡可能均衡地分配在不同CPU 內(nèi)核上的目的。
表2 解析幀數(shù)據(jù)結(jié)構(gòu)Tab.2 Data structure of parsing frame
具體規(guī)則為:對于跨解析幀參數(shù)所在的解析幀,不進行拆分;對于不含跨解析幀參數(shù)的每一類解析幀,將其按參數(shù)個數(shù)等分為n-1 段,其中n為CPU 核數(shù)。采用下取整對參數(shù)個數(shù)進行拆分,相同解析幀類型只拆分一次,后續(xù)不再拆分。
在主線程和子線程之間建立緩存隊列,可以實現(xiàn)主線程和子線程并行工作,有效提高主線程和子線程的工作效率。緩存隊列采用環(huán)形隊列結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)和示意圖分別如表3 和圖5 所示。相較于普通隊列,環(huán)形隊列能夠有效利用資源,避免假滿隊列的情況出現(xiàn),空間利用率更高。其方法為:
表3 緩存數(shù)據(jù)結(jié)構(gòu)Tab.3 Data structure of cache region
圖5 環(huán)形數(shù)組示意圖Fig.5 Diagram of annular array
(1)確定環(huán)形隊列在算法中的使用部位:用于主線程和各子線程之間的共享數(shù)據(jù)緩存,即各幀及幀片段的解析結(jié)果。
(2)完成環(huán)形隊列數(shù)據(jù)結(jié)構(gòu)設(shè)計,利用head 作為環(huán)形數(shù)組的頭部標(biāo)識,tail 作為環(huán)形數(shù)組的尾部標(biāo)識。
(a)入隊:先判斷tail 節(jié)點的下一個位置是否是head,如果是,就表示隊列已滿,無法入隊;如果不是,就可以入隊,即將元素放入tail 的下一個位置,最后將tail 加1(為了能夠在tail 增加到數(shù)組尾部時能夠轉(zhuǎn)回到首部,這里需要將tail 加1 與隊列的大小取余再賦值給tail);
(b)出隊:先判斷tail 和head 是否相等,如果相等,就表示隊列已空,無元素可出,不等則表示非空。此時需要取出head 對應(yīng)位置的元素,然后將head 加1(為了能夠在head 增加到數(shù)組尾部時能夠轉(zhuǎn)回到首部,這里需要將head 加1 與隊列的大小取余再賦值給head)。
同時,多線程在設(shè)計時需要保證共享數(shù)據(jù)操作的完整性,即保證在任一時刻,只能有一個線程訪問該對象。通過對資源池進行分析,將需要上鎖的資源定位于環(huán)形隊列,在鎖定與解鎖資源時遵循以下原則:
(1)當(dāng)更新對象域的時候總是鎖定;
(2)當(dāng)訪問可能更新的對象域的時候總是鎖定;
(3)當(dāng)調(diào)用其它對象方法的時候總是鎖定;
(4)資源使用完畢后及時解鎖,釋放資源。
在多線程技術(shù)中,用戶需要根據(jù)任務(wù)或程序的需要創(chuàng)建線程。創(chuàng)建解析線程分為以下幾步:
(1)創(chuàng)建主線程,流程如圖6(a)所示;
(2)在程序中為每個核創(chuàng)建一個線程;
(3)主線程和子線程同步執(zhí)行,子線程聽從主線程分配任務(wù),流程如圖6(b)所示。
選取某型號試驗數(shù)據(jù)后處理解析軟件,分別形成單線程參考版本和多線程測試版本,在單CPU 八核電腦上對多線程功能進行測試,基于單線程運行結(jié)果,對多線程性能及結(jié)果進行評估,多線程性能測試環(huán)境如表4 所示。
表4 多線程性能測試環(huán)境Tab.4 Muti-thread performance test environment
經(jīng)測試,多線程的加速比和CPU 利用率效果對比如表5 所示??梢钥闯?通過在不同數(shù)據(jù)源下對多線程模塊進行測試,在單CPU 八核電腦上算法加速比不低于49%,CPU 利用率提升不低于260%。
表5 多線程測試結(jié)果Tab.5 Muti-thread test results
通過對多線程的遙測原碼后處理解析的關(guān)鍵技術(shù)進行研究,采用多線程技術(shù)優(yōu)化后處理軟件,可得到較顯著的性能優(yōu)化。經(jīng)多線程設(shè)計改進后,該軟件具有較高的執(zhí)行效率,在多核處理器上能夠充分發(fā)揮計算機性能,達(dá)到顯著提升試驗數(shù)據(jù)處理效率的目的。