看門狗在多進程應用程序中的應用。

 相信大多數的程序員或用戶,在Windows中見到類似於下面的親切而又溫馨的提示信息,都不會感到陌生:

“XXX執行了非法操作,將被關閉。要終止程序,請單擊<確定>;要調試程序,請單擊<取消>。”或者,“是否向Microsoft發送錯誤報告?<發送>,<不發送>。”

    如果這個程序運行在無人值守、需要保持連續工作狀態的場合,而其中的bug又一時難以排除,就需要採取應急措施,消除或減少程序出錯造成的影響。本文討論解決這個問題的辦法。

    做過一定硬件開發的人都知道,惡劣的工作環境,帶有缺陷的硬件設計,不完善的算法等內外因素,都可能造成程序“跑飛”,因此專門加裝一個“看門狗”,負責監視程序主體,必要時產生復位中斷,有效地避免設備當機。

“看門狗”的思想,完全可以拿到高級語言編程中來用。基本做法是:設計一個簡單的監視程序做爲主進程,將原來的工作程序作爲子進程,由主進程啓動子進程並監視子進程的運行狀態。子進程在發生嚴重錯誤時不彈出本文開始時描述的對話框,而是悄悄退出。主進程發現子進程退出後,重新啓動子進程。如此反覆。

    在具體實現上,下面以VC爲例說明:

設置子進程爲“靜默模式”

    在系統初始化部分(CWinApp或main中的開頭),調用API函數SetErrorMode

SetErrorMode(SEM_NOGPFAULTERRORBOX);

    保證程序在發生嚴重錯誤時不彈出對話框,無需人工干預,自行退出。

    在主進程中,創建子進程並運行。假定子進程的可執行文件爲work.exe,示意性代碼如下

STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( π, sizeof(pi) ); ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); // Start the child process if (CreateProcess("work.exe", "", NULL, NULL, FALSE, 0, NULL, NULL, &si, π)) { // success … … }

    CreateProcess有10個參數,看起來挺嚇人,其實並不複雜,很容易理解。最後一個參數會返回子進程的ID和句柄等信息,後面就是對進程ID或句柄進行監視。

    定時檢查子進程是否在正常運行。有好幾個API都可以用於對指定ID的進程進行監視,象GetProcessVersion,GetProcessTimes,GetProcessIoCounters等,其中GetProcessVersion最簡單,只有一個參數:

DWORD GetProcessVersion( DWORD ProcessId);

    當子進程已經退出時,該函數返回0。

    更爲“專業”的函數是GetExitCodeProcess,它甚至能告訴我們子進程退出的原因:

BOOL GetExitCodeProcess( HANDLE hProcess, // handle to the process LPDWORD lpExitCode // termination status );

    爲增強系統的可靠性,給工作程序加裝“看門狗”,不失爲一種可行的技術方案。但如果有兩套用戶界面,看起來就有點不那麼專業了。可將子進程設計爲基於console的應用,不帶用戶界面,所有的信息都通過主進程窗口輸出。主進程CreateProcess的第6個參數需加入CREATE_NO_WINDOW項,將子進程隱藏起來。這樣從用戶的角度看起來,就象只存在一個應用程序。

    另一個問題是,如果用戶關閉主進程,如何同時關閉子進程?用TerminateProcess函數固然能結束子進程,但可能會造成內存泄漏等新問題。最好是主進程向子進程發出結束的消息並進行同步,使子進程能夠從容地退出。

    再擴展一下,一個主進程可以同時管理多個子進程。典型的例子是利用多塊網卡進行抓包、分析、處理的系統,將每一塊網卡應用與一個子進程綁定,而主進程負責監視所有的子進程的工作。

    上面的討論涉及到進程間通信(IPC)問題。解決的辦法有很多,象file mapping, mailslot, pipe, DDE, COM, RPC, cliPBoard, socket, WM_COPYDATA等都能達到目的,可根據個人喜好和具體情況採用。

發佈了28 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章