《電子技術應用》
您所在的位置:首頁 > 其他 > 設計應用 > 基于分布式環境的子進程監控軟件設計與實現
基于分布式環境的子進程監控軟件設計與實現
來源:微型機與應用2013年第7期
張 虎,黃海于
(西南交通大學 信息科學與技術學院,四川 成都 610031)
摘要: 針對分布式系統環境下,計算資源代理對其子進程監控的方法單一,且不能準確獲取子進程運行狀態的問題,提出了一種根據子進程的窗口句柄定時檢測子進程運行狀態的方法。該方法首先根據子進程的不同類型采用不同的方法獲取子進程的窗口句柄,然后根據子進程的窗口句柄定時獲取子進程的運行狀態,最后將傳統的等待子進程退出的方法引入到本應用中。運行結果表明,本方法可以及時準確檢測出Windows環境下子進程的運行狀態,并在子進程異常退出時,可以準確地獲取其異常退出碼。
Abstract:
Key words :

摘  要: 針對分布式系統環境下,計算資源代理對其子進程監控的方法單一,且不能準確獲取子進程運行狀態的問題,提出了一種根據子進程的窗口句柄定時檢測子進程運行狀態的方法。該方法首先根據子進程的不同類型采用不同的方法獲取子進程的窗口句柄,然后根據子進程的窗口句柄定時獲取子進程的運行狀態,最后將傳統的等待子進程退出的方法引入到本應用中。運行結果表明,本方法可以及時準確檢測出Windows環境下子進程的運行狀態,并在子進程異常退出時,可以準確地獲取其異常退出碼。
關鍵詞: 分布式系統;Windows運行環境;代理;子進程的管理和監控;窗口句柄

 隨著高速列車仿真模擬、物聯網應用等領域對計算機計算速度要求的不斷提高,單個的計算機已無法滿足高計算速度的要求。將一個大的計算任務分解成若干個小的計算任務,并利用分布式系統[1]將各計算任務分散到不同的計算機上,以獨立進程的形式進行并行計算是一種比較好的解決方法。而對各獨立進程的運行狀態的實時監控和管理是實現分布式系統高效運行和管理的基礎。但是傳統的子進程監控只能對子進程是否正在運行或者退出做出判斷,無法判斷子進程是否處在掛起狀態,也無法及時地獲取子進程的退出碼。
 針對上述需求,本文提出了一種根據子進程的窗口句柄來檢測當前子進程運行狀態的方法,并結合傳統的子進程管理監控方法,設計并實現了一種實時的子進程管理監控軟件。該軟件用于啟動和監控分布式系統中任務調度器分配給本機的任務。目前該軟件可以檢測子進程的三個狀態:正常運行、退出、掛起;可以及時的將子進程的退出碼[2]反饋給分布式系統的任務調度器,為任務調度器[3]高效利用計算資源提供了一定的依據;并且為開發人員根據進程的異常退出碼對程序進行查錯提供了方便。
1 傳統子進程監控方法
 通常Windows系統使用CreateProcess函數來新建一個子進程。其中CreateProcess函數的最后一個參數的類型是LPPROCESS_INFORMATION結構體,成功創建子進程后,子進程的基本信息就存儲在該結構體中。在Windows API的定義中,該結構體包含了子進程的進程句柄、進程ID、主線程句柄和主線程ID。創建子進程成功后可以通過子進程的句柄和Windows提供的wait[4]系列函數等待子進程或者子進程組變為signaled狀態,從而立刻獲知該進程或進程組退出。
 傳統的子進程監控方法的好處是:如果子進程確實正常退出,則該方法能夠及時地獲知子進程已經退出,并且可以通過Windows提供的API函數GetExitCodeProcess獲取子進程的退出碼。但是在大量的實際應用過程中,該方法暴露出了其不足之處。例如,創建一個有錯的(如除0錯誤)MFC程序,然后通過以上方法啟動這個有錯的進程,再用wait系列函數等待子進程退出。當子進程運行到錯誤的語句時會彈出一個錯誤窗口,如圖1所示。

 這時wait系列函數沒有返回,說明子進程還處在nonsignaled狀態。用GetExitCodeProcess函數獲取該子進程的退出碼時,得到的退出碼為STILL_ACTIVE,也就是說父進程認為子進程還在正常運行,無法獲取子進程的退出碼。
 如果在分布式系統中出現這種子進程明明已經出錯導致無法繼續運行,但是其監控系統認為其還在正常運行的情況,會嚴重影響分布式系統的負載均衡,不利于分布式系統高效的運行和管理。
2 判斷子進程的類型
 Windows支持兩種類型的應用程序。一種是基于圖形用戶界面(GUI)的應用程序,另一種是基于控制臺用戶界面(CUI)的應用程序[5]。
 基于控制臺的應用程序屬于文本操作的應用程序。它通常不能用于創建窗口和處理消息,并且不需要圖形用戶界面。雖然基于CUI的應用程序包含在屏幕上的窗口中,但是窗口只包含文本。命令外殼程序CMD.exe是典型的基于CUI的應用程序。基于GUI的應用程序有一個圖形前端程序,它能創建窗口,擁有菜單,可以通過對話框與用戶打交道,并且可以使用所有的標準Windows組件。
 這兩種類型的應用程序之間的界限是非常模糊的,所以Windows沒有提供API用來判斷一個程序是基于GUI的還是CUI的。但是可以通過應用程序在運行時加載的動態庫[6]來判斷應用程序的類型。
 user32.dll和comctl32.dll兩個模塊[7]是Windows用戶界面相關應用程序接口,包括窗口消息處理,基本用戶界面等特性。結合大量的測試得出,基于GUI的應用程序在運行時肯定會加載這兩個模塊,而單純的基于CUI的應用程序在運行時是不會加載這兩個模塊的。因此,可以通過檢測代理,新啟動的應用程序是否加載了user32.dll和comctl32.dll這兩個模塊來區分應用程序類型。
 接下來的工作就是如何檢測新啟動的進程加載了哪些模塊。在Windows API中提供了枚舉一個進程所加載模塊句柄的接口:EnumProcessModules函數。該函數的原型為:
BOOL WINAPI EnumProcessModules(
  __in          HANDLE     hProcess,
  __out         HMODULE * lphModule,
  __in          DWORD      cb,
  __out         LPDWORD   lpcbNeeded
);
 該函數接收一個進程的句柄,輸出該進程所加載的所有模塊的句柄數組,并且通過lpcbNeeded參數輸出所有模塊的句柄所占的字節數。因為在啟動子進程的時候,肯定能夠得到子進程的進程ID和進程句柄,所以通過EnumProcessModules函數可以方便地得到某個特定的進程所加載模塊的句柄。但是通過模塊的句柄,還無法直觀的得到進程加載的模塊的名稱。這種情況下,可以通過vc提供的另外一個接口:GetModuleFileNameEx函數來獲取各模塊的名稱。GetModuleFileNameEx的函數原型為:
DWORD WINAPI GetModuleFileNameEx(
  __in          HANDLE   hProcess,
  __in          HMODULE hModule,
  __out         LPTSTR    lpFilename,
  __in          DWORD    nSize
);
 該函數接收一個進程的句柄和模塊的句柄,通過lpFilename參數以字符串的形式輸出模塊的具體名稱。進程的句柄在啟動進程時就可以獲得,模塊的句柄就是之前通過EnumProcessModules函數獲得模塊句柄數組。
 計算資源上運行的代理通過這兩個API的配合使用,可以準確獲得啟動的子進程所加載的模塊具體的名稱,也就能夠確定子進程是否加載了user32.dll和comctl32.dll兩個模塊。這樣代理就可以確定子進程是基于GUI的應用程序還是基于CUI的應用程序。在確定了應用程序的類型之后,根據各種類型應用程序的不同特點,采用不同的子進程監控方法對其進行監控。
3 基于窗口句柄對子進程監控的方法
 在Windows系統中不論是GUI應用程序還是CUI應用程序,在程序啟動時都會生成一個窗口。不同的是,GUI應用程序是根據自己的程序需求生成窗口,CUI應用程序是系統為其加載的一個文本控制臺窗口。系統為每一個窗口生成了唯一的標示,即窗口句柄。而且Windows提供了一個通過窗口句柄來檢測應用程序是否處于掛起狀態的API函數,該函數的原型為:BOOL IsHungAppWindow(HWND hWnd)。該函數接收一個窗口句柄作為輸入參數,并且判斷該窗口所屬的進程是否處于掛起狀態。當進程處于掛起狀態時,函數返回TRUE;當進程處于非掛起狀態時,函數返回FALSE。只要能獲取到進程所對應的窗口句柄,就能夠通過定時調用IsHungAppWindow函數判斷GUI應用程序是否處于掛起狀態。
 但是,在子進程創建的過程中,父進程只能獲取到該子進程的進程句柄和該進程的主線程句柄,無法獲取到子進程所對應的窗口句柄。所以,如何獲取子進程所對應的窗口句柄是基于GUI的應用程序監控方法的關鍵。
 獲取窗口句柄的方法有很多種,本應用中針對GUI應用程序和CUI應用程序的不同特點采用了不同的方法獲取這兩種應用程序的窗口句柄。
3.1 獲取GUI應用程序的窗口句柄
 如果應用程序是一個基于GUI的應用程序,則操作系統在啟動的過程中不會為應用程序創建控制臺窗口,而只是加載應用程序。當基于GUI的應用程序啟動之后,就根據程序自身的需要生成特定的窗口。這樣窗口的進程ID即為應用程序的進程ID。
 針對GUI應用程序的窗口進程ID即為應用程序進程ID的特點,獲取GUI應用程序窗口句柄采用的方法是在創建子進程之后遍歷系統中所有窗口,在遍歷的過程中根據窗口的句柄來獲取窗口所對應的進程的ID;將獲取到的窗口進程ID與創建的子進程的ID進行匹配。如果匹配成功則該窗口就是子進程創建的窗口,可以通過該窗口的句柄調用IsHungAppWindow函數來判斷該子進程是否處于掛起的狀態。
 在遍歷窗口句柄時,是通過GetTopWindow和GetNextWindow這兩個API函數協同工作完成的;而根據窗口句柄來獲取窗口所對應的進程ID是通過GetWindowThreadProcessId函數實現的。具體的實現代碼如下:
HWND GetWindowHandleByPid(DWORD dwProcessID)
{
    HWND h=GetTopWindow(0);
    while(h)
    {
        DWORD pid=0;
        DWORD dwThreadID=GetWindowThreadProcessId(h,&pid);
        if(dwThreadID!=0)
        {
            if(pid==dwProcessID)
            {
                return h;
            }
        }
        h=GetNextWindow(h,GW_HWNDNEXT);
    }
    return NULL;
 }
 該函數的輸入參數為需要獲取窗口句柄的進程的ID。如果查找成功則返回進程所對應窗口的窗口句柄;如果不成功則返回NULL。
3.2 獲取CUI應用程序的窗口句柄
 通常情況下,基于CUI的應用程序不會創建窗口和處理消息,并且不需要圖形用戶界面。但是Windows系統會為CUI的應用程序自動加載一個文本控制臺窗口的外殼程序。CUI應用程序的標準輸入輸出都是在這個外殼程序中完成的,所以也可以通過判斷該控制臺窗口是否處于掛起狀態來判斷CUI應用程序的狀態,即通過IsHungAppWindow函數來判斷應用程序是否掛起。
 但是,Windows對CUI應用程序的這種處理方式使得CUI程序與CUI程序的窗口具有不同的進程ID。這樣就不能通過匹配程序進程ID和窗口進程ID的方法來確定某一個窗口是否屬于某一個應用程序。
針對CUI應用程序的以上特點,本應用獲取CUI應用程序窗口句柄的方法是通過檢測窗口的標題來確定該窗口是否屬于某一個CUI程序。采用這種方法的原因是基于CUI的窗口標題肯定為該CUI程序的絕對路徑,并且在分布式計算的環境下,各個任務的子進程可能同名但是肯定是存在于不同的目錄下的。所以通過標題來確定一個窗口是否屬于CUI程序在本應用環境下完全可行。
基于CUI子進程的監控方法是在啟動子進程之后,根據子進程的絕對路徑調用FindWindow系統函數來獲取該CUI子進程的窗口句柄,這樣就可以通過定時調用IsHungAppWindow函數來檢測應用程序的運行狀態。
4 與傳統方法相結合的子進程監控方法
 以上介紹了通過窗口句柄對各種子進程運行狀態監控的可行性。但是,基于窗口句柄檢測子進程運行狀態的方法是定時檢測子進程的運行狀態。所以如果定時檢測的時間較長時,則缺乏好的實時性;如果定時檢測的時間較短時,則增加了計算資源的負載。本應用在綜合考慮了以上問題之后,采用了定時檢測子進程的運行狀態和開辟新的線程等待子進程退出兩種手段相結合的方法來監控子進程的運行狀態。這樣同時確保了檢測子進程運行狀態的實時性又彌補了傳統子進程檢測方法在子進程出現掛起狀態時無法檢測的問題。
在分布式計算環境下,計算資源上的代理啟動子進程的時間不確定,并且可能同時管理多個子進程。所以為了方便管理,在本應用中建立了帶頭結點的子進程信息鏈表用于同時管理多個子進程。鏈表的結構體定義如下:
struct ProcessInfoList
{
     short int ProjectID; //進程工程號
     short int ConditionID; //進程工況號
     short int ModuleID;   //進程模塊號
     short int flag;    //進程運行狀態。-1為未響應;
 //0為已退出;1為正在運行
 HWND hProcessWND;     //進程對應的窗口句柄
 int ProcessType; //進程的類型。1為GUI應用程序;
 //0為CUI應用程序
 int SendFlag;     
   //用于標示是否已經提示調度器該進程已掛起
     PROCESS_INFORMATION  ProcessInfo; 
 //進程的信息,包括進程句柄和進程ID等
     DWORD ExitCode;   //進程退出時的退出碼
     TaskHistoryList *next;
};
 其中ProjectID、ConditionID、ModuleID在整個分布式計算系統中確定唯一一個子進程,并且子進程的可執行文件根據這三個值的不同而存放在不同的目錄下。SendFlag變量是用于提示調度器該進程是否已掛起,當該值為1時,說明已經提示調度器該進程掛起,不用重復提醒;當該值為0時,說明還未提示調度器該進程已掛起。
4.1 定時檢測子進程的運行狀態
 代理啟動時會創建子進程信息鏈表頭結點,并會創建定時器T,定時遍歷子進程信息鏈表。當子進程信息鏈表中除頭結點外沒有其他的結點時,則等待下一次定時的到來;當子進程信息鏈表中除頭結點外還有其他進程的信息結點,則首先關閉定時器T;然后遍歷鏈表各個結點中的窗口句柄信息,根據進程的窗口句柄判斷進程是否處于掛起的狀態,如果進程處于掛起的狀態,則及時將該進程的信息及進程的當前運行狀態發送給調度器,如果進程沒有處于掛起狀態,則繼續遍歷下一個結點,最后遍歷完成之后重新創建定時器T,定時遍歷子進程信息鏈表。經過大量的實驗,最終將定時器的定時時間設為3 s,即每3 s檢查所有子進程是否處于掛起狀態。
4.2 創建新的線程等待子進程退出
 當有任務提交給代理時,代理首先啟動相應的應用程序,然后創建新的線程等待子進程的退出,最后判斷子進程的類型,獲取進程的窗口句柄,為新啟動的應用程序創建子進程鏈表節點。其中等待子進程退出線程中所做的工作有:(1)根據新啟動進程的進程句柄調用WaitForSingleObject函數,等待子進程的退出;(2)當子進程退出后獲取進程的退出碼,并存放在相應的子進程信息鏈表結點中;(3)獲取退出碼之后,將該子進程的基本信息、子進程的當前狀態、子進程的退出碼發送給調度器,線程結束。
 以上介紹了在Windows系統環境下對基于GUI和基于CUI子進程監控的實現方法。該方法主要是通過定時檢測子進程對應的窗口是否掛起以及開辟新的線程等待子進程退出兩種手段相結合的方式實現對子進程的監控。雖然通過定時檢測窗口是否掛起的方法存在缺乏實時性的問題,但是通過縮短定時時間也可以將時間控制在毫秒級,在絕大多數的分布式計算應用系統中是可以接受的。
該方法解決了傳統的子進程檢測方法無法檢測子進程掛起狀態的問題。對子進程運行狀態的檢測更準確,提高了分布式計算環境下的資源利用率。
參考文獻
[1] 葛澎.分布式計算技術概述[J].微電子學與計算機,2012(5):201-204.
[2] DAVE T. Understanding exit codes[J]. Linux Journal, 2010(197):24-25.
[3] Xie Tao, Qin Xiao. A Security-qriented task scheduler for heterogeneous distributed systems[J]. Lecture Notes in Computer Science, 2006(4297):35-46.
[4] STRVENS W R, RAGO S A. UNIX環境高級編程(第2版)[M].尤晉元,張亞英,戚正偉譯.北京:人民郵電出版社, 2005:179-182.
[5] RICHTER J, NASARRE C. Windows核心編程(第5版)[M].葛子昂,周靖,廖敏譯.北京:清華大學出版社,2008:69-72.
[6] 高連生,盛柏林.動態鏈接庫在組態軟件中的應用[J].工業控制計算機,2010(6):21-22.
[7] 周超.Windows和Linux動態鏈接庫研究及應用[D].上海:華東理工大學,2007.
[8] Microsoft. QIsHungAppWindow function(Windows) [OL]. [2012-11-28]. http://msdn.microsoft.com/ZH-CN/library/windows/desktop/ms633526(v=vs.85).aspx

此內容為AET網站原創,未經授權禁止轉載。
亚洲一区二区欧美_亚洲丝袜一区_99re亚洲国产精品_日韩亚洲一区二区
欧美精品日韩精品| 国产一二三精品| 久久国产手机看片| 亚洲午夜小视频| 亚洲伦理精品| 亚洲精品日韩久久| 亚洲精品国产精品国自产在线| 久久国产精品网站| 欧美一区激情| 久久激情视频久久| 久久精品日产第一区二区| 欧美一区二区三区啪啪| 香蕉免费一区二区三区在线观看| 亚洲在线不卡| 亚洲在线网站| 亚洲欧美中日韩| 午夜精品视频一区| 性欧美精品高清| 欧美日韩一二区| 久久久久.com| 蜜桃久久精品一区二区| 免费影视亚洲| 欧美激情第一页xxx| 欧美区视频在线观看| 欧美日韩免费观看一区| 欧美日韩综合不卡| 国产精品入口麻豆原神| 国产欧美一区二区三区久久人妖 | 欧美日韩免费观看中文| 欧美日韩少妇| 国产伦精品一区二区三区在线观看| 国产视频亚洲| 狠狠做深爱婷婷久久综合一区| 狠狠网亚洲精品| 91久久中文字幕| 日韩一级网站| 亚洲欧美激情视频在线观看一区二区三区| 亚洲欧美不卡| 亚洲国产黄色| 亚洲社区在线观看| 久久成人综合网| 蜜臀久久久99精品久久久久久| 欧美精品自拍| 国产精品一级久久久| 韩日欧美一区| 亚洲精品四区| 羞羞色国产精品| 亚洲区国产区| 亚洲欧美日韩成人| 蜜桃av综合| 国产精品久久久久久久一区探花| 国产一区二区高清| 亚洲国产影院| 午夜精品久久久久影视 | 国产综合激情| 亚洲日本成人网| 香蕉成人伊视频在线观看| 亚洲娇小video精品| 亚洲综合精品四区| 久久嫩草精品久久久精品一| 欧美全黄视频| 国产一区二区丝袜高跟鞋图片| 亚洲片在线资源| 欧美不卡视频| 欧美视频在线观看视频极品| 欧美日韩高清不卡| 国产一区二区三区在线观看免费| 亚洲精品一级| 久久精品72免费观看| 亚洲影院免费| 免费看av成人| 国产欧美精品xxxx另类| 亚洲三级影片| 久久国产88| 午夜精品久久久久久久99水蜜桃| 欧美成人精品激情在线观看| 国产日本欧美一区二区三区在线| 亚洲国产婷婷| 久久精品一区二区三区中文字幕 | 亚洲最黄网站| 亚洲国产另类久久久精品极度| 亚洲在线网站| 欧美片第一页| 在线看片一区| 欧美在线一区二区| 午夜老司机精品| 欧美日韩久久不卡| 亚洲大片在线| 欧美在线不卡| 亚洲欧美在线播放| 欧美日韩国产精品成人| 在线观看亚洲视频啊啊啊啊| 亚洲欧美日韩在线| 亚洲午夜久久久| 欧美精品少妇一区二区三区| 精品1区2区3区4区| 欧美在线观看日本一区| 欧美一级视频精品观看| 欧美婷婷久久| 亚洲人成人一区二区三区| 亚洲国产婷婷香蕉久久久久久99| 久久国产精品久久w女人spa| 国产精品久久久久久影院8一贰佰 国产精品久久久久久影视 | 久久福利资源站| 国产精品高潮在线| 9i看片成人免费高清| 亚洲美女在线视频| 欧美不卡在线视频| 激情另类综合| 欧美中日韩免费视频| 欧美在线视频不卡| 国产精品美女在线观看| 宅男精品视频| 亚洲天堂av电影| 欧美日韩亚洲系列| 日韩网站在线观看| 一区二区三区高清| 欧美精品在线观看播放| 亚洲区中文字幕| 亚洲裸体视频| 欧美剧在线免费观看网站| 最新国产の精品合集bt伙计| 最新亚洲激情| 欧美—级在线免费片| 亚洲精品欧美| 亚洲一区二区少妇| 国产精品hd| 亚洲欧美中文日韩在线| 久久久国产精品亚洲一区| 国产午夜精品一区二区三区欧美| 性欧美暴力猛交69hd| 久久久www免费人成黑人精品 | 久久先锋资源| 在线欧美日韩精品| 夜夜爽av福利精品导航| 欧美午夜免费影院| 午夜伦欧美伦电影理论片| 久久手机免费观看| 亚洲国产美女| 亚洲午夜免费福利视频| 国产精品视频yy9299一区| 欧美一区国产一区| 欧美成人精品激情在线观看| 99riav国产精品| 性久久久久久久| 国内揄拍国内精品少妇国语| 亚洲激情网站免费观看| 欧美日韩成人网| 亚洲欧美日韩国产综合| 久久全国免费视频| 亚洲肉体裸体xxxx137| 亚洲影院在线| 国产一区成人| 夜夜嗨av一区二区三区网站四季av | 国产一区二区三区在线观看精品| 亚洲第一伊人| 欧美日韩一区视频| 午夜一区二区三视频在线观看| 久久亚洲午夜电影| 亚洲精品一区二区三区四区高清| 欧美亚洲三区| 在线观看日韩av先锋影音电影院| 在线一区二区视频| 国产日韩高清一区二区三区在线| 亚洲黄色精品| 国产精品国产三级国产aⅴ浪潮 | 亚洲电影有码| 欧美午夜视频| 亚洲电影av| 国产精品久久久久久久久搜平片 | 在线观看视频亚洲| 亚洲伊人第一页| 樱花yy私人影院亚洲| 亚洲一区二区在线免费观看| 国产亚洲精品成人av久久ww| 日韩小视频在线观看专区| 国产精品系列在线播放| 日韩亚洲不卡在线| 国产亚洲欧美另类一区二区三区| 一本色道久久综合亚洲91| 国产一区二区无遮挡| 亚洲一区高清| 在线看国产日韩| 新片速递亚洲合集欧美合集| 91久久久久久久久久久久久| 久久久www| 亚洲一级黄色片| 欧美日韩精品免费观看视一区二区| 欧美在线精品一区| 国产精品成人在线| 亚洲人成亚洲人成在线观看| 国产伦精品一区二区三区视频孕妇 | 亚洲图片欧美午夜| 欧美.日韩.国产.一区.二区| 亚洲男女自偷自拍| 欧美日韩视频免费播放| 亚洲精品精选| 好吊妞这里只有精品| 午夜精品久久久久久久白皮肤 | 国产精品私人影院|