甘 嵐,鄭 鵬,高 捷,王雪虎,于忠平
受目前人工智能技術發展的限制,當今各種醫療圖像處理軟件在診斷準確率上的差異不是很大[1]。同時,醫療診斷是否及時,關系著患者的健康甚至能否被治愈。所以處理時間越短,越具有實用性和市場競爭力。
一般說來,在圖像處理和進行特征統計的過程中,需要對位圖的像素進行多次遍歷操作。這些操作一般通過循環來實現。當位圖較大時,循環次數非常多,非常耗時。
本文通過把輸入的位圖分割成若干小圖,每塊圖用一個線程進行處理,一方面縮小了每個線程處理問題的規模;一方面增加程序的并行性,更加充分地利用多處理器體系結構,提高程序的執行效率,從而達到縮短處理時間的目的。文中還對該方法引起的誤差進行了分析,提出折中的方案。
進一步分析系統工作原理,在輸入位圖后,圖像處理功能模塊對圖像進行處理并輸出統計信息。圖像處理模塊的核心是特征統計子模塊。該模塊首先對輸入的數字圖像進行灰度化,然后用松弛迭代算法進行閾值分割,最后再進行邊界跟蹤,統計周長、面積等特征信息。系統工作流程如圖1所示,可以看出這是一個串行結構。
分析這段子模塊的源代碼,灰度化、閾值分割、邊界跟蹤和統計分別通過CBmpImage類的成員函數ColorToGray()、LosseRepeat(LPSTR lpDIB,int k)和ForAreaTrackNuclear(int minvalue,int maxvalue,bool remove)實現。這3個函數代碼中用到遍歷數字圖像像素的for循環共17個,而且這些for循環中有不少是兩重以上的嵌套。在圖像像素值較大時,這些代碼的運行就非常費時。以實現邊界跟蹤和統計功能的ForAreaTrackNuclear函數為例,關鍵代碼如下:


圖1 圖像處理工作流程圖

這段代碼包含了兩重for循環,時間復雜度為O(n2)。例如,當圖像長寬都為100像素時,for循環中的代碼執行10 000次;當圖像長寬都為200像素時,循環中的代碼執行40 000次。可見看出當圖像稍大時,計算開銷非常大。對于更多層的嵌套,時間復雜度會更大,時間消耗的增長速度將更快。
從流程圖中可以看出,程序是一個串行結構,查看源程序,也可以證實這一點。即ColorToGray()、LosseRepeat(LPSTR lpDIB,int k)和ForAreaTrackNuclear(int minvalue,int maxvalue,bool remove)函數后面的函數需要前一程序處理的結果作為輸入,根據Amdahl定律,這即使程序運行在多核處理器機器上也不能得到很好的加速比。
圖像處理模塊因為要對像素進行遍歷操作含有大量的for循環,其中包含了不少嵌套結構。從時間復雜度來看,設q是嵌套的層次數,則嵌套的for循環的時間復雜度為O(nq),使得運行時間增長顯著。
綜上所述,特征統計子模塊由于有大量for循環和串行結構,成為影響速度的瓶頸模塊。
多線程的優點之一是能充分使用多處理器體系結構,以便每個線程能并行運行在不同的處理器上[2]。根據Amdahl定律和Gustafson定律[3],在多核平臺上,增加程序的并行性能獲得良好的加速比,縮短運行時間。目前多核CPU已經越來越普及,雙核處理器已成為當下主流中低檔PC機配置。采用多線程技術可以充分發揮多處理器電腦的硬件優勢,提高運行速度。另外,在單CPU的情況下,多線程技術的使用可以提高計算機資源的利用率,從而提高程序運行速度。所以本文嘗試應用多線程技術來對特征統計子模塊進行改造,提高運行的速度,并在單核核多核平臺上進行驗證。
經過分析圖像處理模塊的代碼可以發現處理算法的各步驟間有著嚴密的順序關系,后一步的處理依賴上一步的處理結果,這就使得改造時不能采用各步并發執行的方法。進一步發分析代碼,可以發現這一模塊中耗時較多的原因是在預處理、灰度化、分割和跟蹤中需要對位圖中每個像素進行掃描和處理,計算量比較大。要想提高速度,可以考慮降低計算量。如果把需要處理的位圖面積減小,掃描的量就降低了,計算量也就下降了。如果利用多線程技術并發執行每個小圖,最后把結果匯總就可能得到大圖的處理結果。經過有關實驗驗證,這種方法是可行的。
另外,由于多線程執行的并發性(單核平臺上并不是嚴格意義上的并發),如果多個線程在執行過程中訪問了相同的資源,就可能造成一些無法控制的錯誤[4]。比如某線程在對一變量先進行寫操作,然后再讀取。當它寫入了數據后,分配給它的CPU時間片用完,下一線程開始執行,如果正在執行的線程對同一變量進行了寫操作,就會覆蓋上一線程的寫入值,從而使得上一線程下次執行讀操作時出現問題。在VC++中可以通過互斥對象、事件對象和關鍵代碼段等手段避免這種錯誤,但是會影響執行的速度和效率,增加額外的系統開銷,當線程比較多時反而造成較多的浪費。所以在對單線程程序進行多線程改造時,要盡量避免對同一資源的并發訪問[5]。
本系統基于MFC開發,可以利用其多線程機制來實現多線程的改造。MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區別在于工作者線程沒有消息循環,而用戶界面線程有自己的消息隊列和消息循環。
工作者線程沒有消息機制,通常用來執行后臺計算和維護任務,如冗長的計算過程,打印機的后臺打印等。用戶界面線程一般用于處理獨立于其他線程執行之外的用戶輸入,響應用戶及系統所產生的事件和消息等。但對于Win32的API編程而言,這兩種線程是沒有區別的,它們都只需線程的啟動地址即可啟動線程來執行任務[6]。
在MFC中,一般用全局函數AfxBeginThread()來創建并初始化一個線程的運行,該函數有兩種重載形式,分別用于創建工作者線程和用戶界面線程。兩種重載函數原型和參數分別說明如下:
(1)CWinThread*AfxBeginThread(AFX-THREADPROC pfnThreadProc,LPVOID pParam,
nPriority=THREAD-PRIORITY-NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY-ATTRIBUTES lpSecurityAttrs=NULL);
pfnThreadProc:指向工作者線程的執行函數的指針,線程函數原型必須聲明如下:
UINT ExecutingFunction(LPVOID pParam);
請注意,ExecutingFunction()應返回一個UINT類型的值,用以指明該函數結束的原因。一般情況下,返回0表明執行成功。
pParam:傳遞給線程函數的一個32位參數,執行函數將用某種方式解釋該值。它可以是數值,或是指向一個結構的指針,甚至可以被忽略。
nPriority:線程的優先級。如果為0,則線程與其父線程具有相同的優先級。
nStackSize:線程為自己分配堆棧的大小,其單位為字節。如果nStackSize被設為0,則線程的堆棧被設置成與父線程堆棧相同大小。
dwCreateFlags:如果為0,則線程在創建后立刻開始執行。如果為CREATE-SUSPEND,則線程在創建后立刻被掛起。
lpSecurityAttrs:線程的安全屬性指針,一般為NULL。
(2)CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,
int nPriority=THREAD-PRIORITY-NOR MAL,
UINT nStackSize=0,
DWORD dwCreateFlags=0,
LPSECURITY-ATTRIBUTES lpSecurityAttrs=NULL);
pThreadClass是指向CWinThread的一個導出類的運行時類對象的指針,該導出類定義了被創建的用戶界面線程的啟動、退出等。
其它參數的意義同形式(1)。
一般情況下,調用AfxBeginThread()來一次性地創建并啟動一個線程,但是也可以通過兩步法來創建線程:首先創建CWinThread類的一個對象,然后調用該對象的成員函數CreateThread()來啟動該線程。
MFC應用程序的線程由對象CWinThread表示。在多數情況下,程序不需要自己創建CWinThread對象。調用AfxBeginThread函數時會自動創建一個CWinThread對象。本文對原程序的改造就使用了這種創建進程的方法。
2.3.1 對輸入圖像的分割
根據2.1節的思路,先把待處理圖像根據處理線程的多少分成和線程數相等的子圖,然后對每個子圖分別用一個線程進行處理、統計。
對輸入圖像的分割(用多少個線程處理就分成多少塊)在CimageView類中的OnLButtonUp消息相應函數中實現,以下是其中的關鍵代碼,實現從原圖像中截取一塊子圖的功能:

2.3.2 信息的傳遞和綜合
截取了子圖后,要把子圖的句柄傳遞給多線程函數進行圖像處理和特征統計。為了避免多線程運行時多個線程訪問相同的資源,分別用不同的全局變量記錄這些句柄,每個處理子圖的線程啟動后通過全局變量訪問自己要處理的子圖像。
為了方便對各個線程得到的統計結果進行綜合,同時也避免多線程訪問沖突,每個處理子圖的線程處理結果記錄在不同的全局變量里。當所有線程運行結束(記錄子圖統計結果的各全局變量都被更新),訪問這些記錄了統計結果的全局變量,進行綜合匯總得到整幅圖的統計信息。
處理子圖像的線程通過調用AfxBeginThread函數創建并啟動,圖像處理識別的代碼添加到線程的處理函數ThreadFunc(LPVOID lpParam)中(代碼略)。
調用AfxBeginThread函數啟動多線程的部分代碼如下:

調用的個數和線程數相同,程序中用switch語句控制。
2.3.3 運行時間的獲取
為了定量分析程序和線程的運行時間,需要一定精度的計時器。在Windows平臺下,常用的計時器有兩種,一種是timeGetTime多媒體計時器,它可以提供毫秒級的計時。但這個精度對本實驗而言太粗糙了,而且受消息響應的影響,誤差較大。另一種是QueryPerformanceCount計數器,隨系統的不同可以提供微秒級的計數。為了得到較準確的實驗數據,本文采用了后者。
QueryPerformanceCount計數器是通過使用QueryPerformanceFrequency()和QueryPerformanceCounter()函數實現的。QueryPerformanceFrequency()函數和QueryPerformanceCounter()函數的原型如下:
BOOL QueryPerformanceFrequency(LARGE-INTEGER*lpFrequency);
BOOL QueryPerformanceCounter(LAR GE-INTEGER*lpCount);
數據類型ARGE-INTEGER既可以是一個8字節長的整型數,也可以是兩個4字節長的整型數的聯合結構,其具體用法根據編譯器是否支持64位而定。該類型的定義如下:

程序中首先調用QueryPerformanceFrequency()函數獲得機器內部定時器的時鐘頻率,然后在線程創建處(計時的起點)和得到統計結果處(計時的終點)各調用一次QueryPerformanceCounter()函數,利用兩次獲得的計數之差除以時鐘頻率,計算出事件經歷的精確時間。定時誤差不超過1微秒,精度與CPU等機器配置有關。
在多核CPU平臺上運行時,不同CPU核的內部計數器不同步。如果程序兩次讀取這個計數器的時候恰好被輪換到不同的核上,那么用來計時就會有比較大的誤差。為解決這個問題,本文采用設定線程親核性的方法。即用函數SetThreadAffinityMask指定某線程只在某些核上運行(由第二個參數設定,每個位代表一個核)。例如,在進行精確計時那個線程里執行SetThreadAffinityMask(GetCurrentThread(),0x00000001);就能保證該線程只在第一個核上運行,不會因為不同CPU核計數器不同步而造成計時誤差[7]。
表1給出了測試平臺的軟、硬件參數。

表1 實驗環境
3.2.1 實驗對象
實驗對像是從采集的組織切片位圖照片庫中隨意選取的4幅大小不同的位圖,如圖2所示。
由于切片染色不同,顏色稍有區別。
3.2.2 實驗指標設計
為了衡量用多線程對程序進行改造后并行運行所獲得的性能收益,定義加速比q=tc/tb:其中:tc表示未進行多線程改造前相應模塊運行的時間,tb表示多線程該著后并行執行的時間。

圖2 實驗位圖圖片及其大小(單位:像素)
n行時間,Nn表示線程個數,n表示試驗的序號。凈節省時間T′表示線程增加后平均每個新增線程的運行時間減小量,反映了新增線程對縮短整體運行時間的貢獻度。T′>0時,說明線程的增加使運行時間縮短,T′值越大,縮短的時間越多,貢獻度越大,效率越高;T′=0時,說明線程的增多不能縮短運行時間;T′<0時,說明線程的增多不但不能提高運行速度,反而使運行時間增加。
n結果,共有4個值:周長在閾值內的細胞核區域個數、平均周長(單位像素)、面積在閾值內的細胞核區域個數和平均面積(單位像素)。p0表示統計結果的正確結果,考慮到誤差,用單線程時的統計結果多次取平均值近似代替,相應也有4個值。所以誤差率 η表示多線程改造后統計結果的誤差量和正確值的比率。
3.2.3 實驗方案和結果處理
對每幅圖分別用單線程和多線程處理,多線程的線程個數從2,4,8,16,32個增加到64個。記錄每次試驗運行的時間和統計結果。每幅圖共進行7組實驗(每換一次線程數為一組)。程序運行時機器是動態運行的,不同時刻機器的軟硬件環境可能會不同,從而使得運行時間有差異。為了保證結果準確,每組試驗相同條件重復5次取平均值,減小偶然誤差對結果的影響。
為了分析程序在多線程改造后在單核和多核CPU平臺上性能的變化,在四核的HP DL580G3企業級服務器上通過windows任務管理器的“處理器關系”設置來選擇執行進程的CPU,分別在單核、雙核和四核情況下按上述實驗方法分別進行實驗。采用這種方法可以盡可能使實驗的軟硬件環境只有CPU核數和線程數的變化,從而更好地比較性能與CPU數和線程數的關系。
3.3.1 加速比與CPU數及線程數的關系
加速比是衡量程序并行運行所獲得的性能收益的指標,由Amdahl定律和Gustafson定律可知,理論上加速比的大小取決于程序中不可并行執行部分所占比例和CPU的數量,具體到本文就是取決于用多少線程改造原模塊和多核CPU的核數。鄭鋒在文[8]中從理論上論證了減少程序中串行部分所占的比例,增加并行部分的比例比增加處理器核數對加速比的貢獻更大。陳勇等人在文[9]中指出多處理器系統中要根據處理器的數量選擇合適的線程數才能較好地提升程序運行速度。本文通過實驗對以上觀點進行驗證,并找出加速比和CPU數及線程數的關系,為線程數和CPU數的選擇提供依據。取單線程、單核CPU環境下運行時間為 tc,多線程改造后運行時間為tb,由q=tc/tb計算出各幅位圖在不同CPU數和線程數下的加速比。發現在相同CPU數和線程數時,加速比因為位圖大小而有一些差別,為便于說明問題,取4個加速比的均值進行比較。實驗結果如表2所示。

表2 平均加速比與CPU數和線程數的關系
從表中可以看出以下幾點:
(1)當線程數等于CPU核數時,加速比隨著線程數或核數的增加近似呈線性增長,即加速比隨著線程數或CPU核數加倍而加倍。
(2)當線程數小于CPU核數時,加速比隨著線程數的增加近似呈線性增長;隨著CPU數的增加有限、緩慢地增長。
(3)當線程數大于CPU核數時,加速比隨著CPU數的增加近似呈線性增長;隨著線程數的增加有限、緩慢地增長。
(4)單獨增加CPU數或線程數都能提高加速比,但單獨增加前者的提高幅度小于后者。
因為不管有多少CPU,單線程進程只能運行在一個CPU上,當CPU數大于線程數時,會有CPU閑置;而當線程數大于CPU數時,會有多個線程競爭一個處理器,從而增加了系統的開銷。所以只有在CPU數等于線程數時,每個處理器處理一個線程,才能使加速比線性增加(本實驗存在一個前提:每個線程的工作量大約均等,優先級相同。如果各CPU上負載不平衡,也會影響并行的效果)。此外,現象(4)驗證了文[8]中增加并行部分的比例比增加處理器核數對加速比的貢獻更大的結論。究其原因,增加線程數從減少程序中串行部分所占的比例和減小處理問題規模兩個方面提高程序的運行速度,其中減小處理問題規模方面與實際處理問題和算法有關,與硬件環境無關。增加CPU數從增加處理器數量一方面增加了程序的加速比,且要受到運行在其上的線程數的制約。考慮到增加處理器數量的成本高于增加線程的成本,且線程數大于處理器數后對加速比仍有一定的提升能力,在選擇處理器和線程的數時,可以讓線程數略大于處理器數。
因此,從盡可能提高加速比的目的出發,在硬件條件許可的情況下,盡量選擇多核處理器,且處理器數量盡可能多。同時線程數大于處理器的數量。
另外對比相同位圖在不同CPU核數條件下和在不同計算機上得到的程序運行速度、效率和線程數關系的折線圖,發現CPU核數和硬件條件的變化對上述關系的影響僅限于折線的高低、拐點出現的線程數及拐點前后折線的斜率,不影響定性分析其中的關系。而對于誤差率和線程數的關系則沒有影響。為于接近一般醫院硬件條件和便于論述,下文以在計算機1平臺上所得到的實驗結果為例來分析上述關系。
3.3.2 程序運行速度與線程數的關系
程序的運行速度用執行時間作為衡量指標,圖3給出了4幅位圖進行處理所需時間和線程數的關系。圖中數據點是在線程為1,2,4,8,16,32和64時實驗所得的數據。

圖3 運行時間折線圖
運行時間折線圖反映了隨著線程增多,處理該位圖消耗時間的變化情況。從中可以看出多線程改造后,運行速度得到提高,運行時間隨線程增多而減少。但是減小幅度隨著線程數的增加越來越小,線程增加對程序速度的提升趨于停頓。這是因為增加線程會增加系統開銷,系統開銷一般由兩部分組成:操作系統實際開銷和線程間的活動開銷,例如線程調度、同步以及其他形式的線程間通信開銷。如果系統開銷比較大,它會抵消因增加線程提高程序并行性帶來的速度提高。從反映新增加線程提高運行速度的效率的凈節省時間公式可以發現凈節省時間實質上描述的是圖中曲線的變化率。從圖4凈節省時間隨著線程數增加趨于零的現象能推測出圖3運行時間的減少是有極限的,并且根據文[10]中實驗結論可以推測到隨著線程數進一步增加,系統開銷的增大將使運行時間反而增加。
3.3.3 多線程的效率與線程數的關系
多線程改造提高運行速度的效率用單個線程平均凈節省時間衡量。實驗結果如圖4。

圖4 單個線程平均凈節省時間折線圖
圖中數據點同樣是在計算機1平臺上線程為1,2,4,8,16,32和64時試驗所得的數據。單個線程平均凈節省時間折線圖反映了隨著線程增加,平均新增一個新線程能節省多少時間。從圖中可以看出隨著線程增加,平均每個線程節省的時間先呈降低趨勢,在10到20線程之間時出現一個短暫回升的趨勢,然后又降低,在線程數較大,如大于30時,平均每個線程節省的時間小于0.1秒,并呈進一步降低趨勢,可以推測線程數更大時平均每個線程節省的時間趨于零,甚至為負值。這里的原因還是如上文分析的,線程的增加增加了系統的開銷,當開銷抵消了因增加線程提高程序并行性帶來的節約時間后,新增線程不但不能降低運行時間,反而增加運行時間。折線圖中短暫的回升原因仍然是線程增加提高并行性節約運行時間和系統開銷隨線程增加而增大增加運行時間這對矛盾的變化。當增加少量線程時,如增加1到2個進程,一方面,增加了程序并行性,提高了運行速度,一方面對操作系統來說負擔并不大,系統開銷主要是線程調度、同步和通信等開銷。所以增加線程后雖然平均每個線程節約時間在降低,但仍然處在一個較高效率上,如圖4所示在第一個下降段前期(線程數小于8)節約時間能維持在0.1秒以上。當線程進一步增多,如增加十幾個線程,對操作系統的壓力仍然不大,但因為線程數目較多,對系統資源如CPU時間的利用更加充分,所以此時凈節省時間有一個回升的趨勢,比之前的拐點值要高出一些。線程進一步增加,如增加到30個以上時,對操作系統產生較大的影響,使系統開銷增長較快,凈節省時間再次下降。
3.3.4 統計結果誤差與線程數的關系
多線程時,由于要把待處理圖像分成若干塊,在子塊的邊緣可能造成細胞截斷等現象,影響周長、面積信息的統計結果。實驗中把每幅位圖在單線程條件下重復運行5次所得的統計結果的平均值作為基準值,和多線程條件下的運行結果比較,得到誤差率。4幅位圖的誤差率如圖5所示。
誤差率折線圖反映了統計的4個特征指標隨線程增加誤差的變化。從圖4中可以看出一定面積核區域個數和一定周長核區域個數兩個指標的誤差規律比較明顯,隨著線程數增多,誤差先反向增大,在拐點處開始減小,過零點后繼續正向增大。平均面積和平均周長雖然折線不如另兩個指標規律明顯,但仍然呈一定的規律:隨著線程增加,誤差率先正向增大,到達拐點后開始減小,并有向負方向增大的趨勢。從總體上看,前兩個指標的誤差率變化幅度比較平緩,且在線程數小于8時,都在30%范圍之內,線程數在20到30之間能夠找到兩者都處于誤差正負30%的范圍內的點。后兩個指標變化比較陡,誤差先以比較快的速度正向增大,然后較緩地反方向減小,在線程數小于8時,誤差表現的比較規律,都是正向誤差,一般不會超過100%,線程大于8時,規律不明顯。
為了利用誤差率的規律性減小誤差,對模塊進行多線程改造時線程數不超過8,相應的CPU的數量也限制在8以內。

圖5 誤差率折線圖
造成統計結果誤差的主要原因是在對原圖像進行分割時,子圖像的邊緣可能會有細胞被截斷,從而影響了統計結果。由于圖像的細胞腺體細胞是聚集的,有一定的粒度,當分塊大小合適時,即選用合適的線程數,可以使大多數細胞不被截斷,還可以從分割帶來的誤差中帶來一定的補償,減小統計結果誤差。據醫院方面試用的反饋信息,誤差率不超過30%時,對醫療輔助診斷影響不大。下面綜合考慮速度、效率和誤差指標,找到比較合適的線程數,使多線程改造造成的誤差在可接受范圍內。
根據3.3節對實驗結果的分析,在實驗條件下,線程數小于20時,多線程對速度的提升比較明顯,且效率也比較高,增加線程帶來的系統開銷與收益相比較小。誤差率的4個指標在線程數小于8時都比較有規律,可以引入一定的補償(即統計結果減去或加上補償量),補償量可以通過某種以統計值為自變量的經驗函數求得。例如,設x為統計值,選用簡單的線性函數y=±α x得到補償量,其中y為補償量;α∈(0,1)為經驗值,可通過試湊法得到;正負號的取值看指標的誤差特點而定,是正向誤差的(即結果比準確值大)取負號,反之取正號。則補償后的統計值 x′可以由公式x′=x±α x得到。
在本實驗條件下,按上述方法進行試湊,發現對一定周長核區域個數、平均周長、一定面積核區域個數和平均面積指標分別用補償函數y=0.1x、y=-0.4x、y=0.2x和y=-0.51x進行補償,可以使得四個指標的誤差率在線程數小于8時全部控制在±30%之內,特別是一定周長核區域個數和一定面積核區域個數兩個指標補償后的誤差率都在±20%之內。
綜合上面的論述,考慮提高加速比和線程效率,控制誤差范圍等因素,在醫院現有設備條件下,得到一個折中的多線程改造方案:選用雙核或四核處理器的計算機作為使用平臺,用4~8個線程對特征統計子模塊進行多線程改造來提高程序的運行速度,同時采用補償函數對統計結果進行補償,使統計結果的誤差在可接受范圍內。
根據所提出的改造方案對系統進行了多線程改進,經過醫院的試用,較好解決了系統運行過慢的問題,輔助診斷的效果也沒有受到影響。
另外,對3.4節的所舉的補償函數進行測試,發現雖然能把補償后的誤差率控制在一定得范圍內,但是難以把誤差率進一步縮小。例如平均面積指標的誤差率在α從小到大的取值過程中,誤差率曲線在線程數小于8的部分會在20%附近波動,無法使所有點的誤差率都下降到20%以內。這說明補償函數的選取過于簡單,對于要達到更高精度的情況,需要尋找更復雜的補償函數。
[1]蔣先剛.顯微圖像處理系統的軟件設計[J].華東交通大學學報,2001,18(1):1-4.
[2]李實,劉乃琦,郭建東.多核架構下的多線程負載平衡[J].計算機應用,2008,28(12):139-140.
[3]SHAMEEM A J R.Multi-core programming[M].Beijing:PublishingHouse of ElectroniesIndustry,2006.
[4]劉邦桂,李正凡.用Java實現流式Socket通信[J].華東交通大學學報,2007,24(5):110-112.
[5]劉權勝,楊洪斌,吳悅.同時多線程技術[J].計算機工程與設計,2008,29(4):963-967.
[6]張智豐,張亞榮,包麗梅.在VC++中利用API實現多線程編程實例[J].內蒙古民族大學學報(自然科學版),2008,23(4):382-385.
[7]NAMIR C S.Secrets of the Visual C++masters[M].Beijing:Tsinghua University Press,1994.
[8]鄭鋒.圖像分析多核并行計算類庫的構建與優化[D].廈門:廈門大學,2008.
[9]陳勇,陳國良,李春生,何家華.SMP機群混合編程模型研究[J].小型微型計算機系統,2004,25(10):1 763-1 767.
[10]郭輝.多線程的效率[J].AJR.計算機應用,2008,28(12):141-143.