zoukankan      html  css  js  c++  java
  • 给应用程序加装“看门狗”

    相信大多数的程序员或用户,在Windows中见到类似于下面的亲切而又温馨的提示信息,都不会感到陌生:

    “XXX执行了非法操作,将被关闭。要终止程序,请单击<确定>;要调试程序,请单击<取消>。”或者,“是否向Microsoft发送错误报告?<发送>,<不发送>。”

    如果这个程序运行在无人值守、需要保持连续工作状态的场合,而其中的bug又一时难以排除,就需要采取应急措施,消除或减少程序出错造成的影响。本文讨论解决这个问题的办法。

    做过一定硬件开发的人都知道,恶劣的工作环境,带有缺陷的硬件设计,不完善的算法等内外因素,都可能造成程序“跑飞”,因此专门加装一个“看门狗”,负责监视程序主体,必要时产生复位中断,有效地避免设备当机。

    “看门狗”的思想,完全可以拿到高级语言编程中来用。基本做法是:设计一个简单的监视程序做为主进程,将原来的工作程序作为子进程,由主进程启动子进程并监视子进程的运行状态。子进程在发生严重错误时不弹出本文开始时描述的对话框,而是悄悄退出。主进程发现子进程退出后,重新启动子进程。如此反复。

    在具体实现上,下面以VC为例说明:

    设置子进程为“静默模式”
    在系统初始化部分(CWinApp或main中的开头),调用API函数SetErrorMode

    SetErrorMode(SEM_NOGPFAULTERRORBOX);保证程序在发生严重错误时不弹出对话框,无需人工干预,自行退出。

    启动子进程
    在主进程中,创建子进程并运行。假定子进程的可执行文件为work.exe,示意性代码如下

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
     
    ZeroMemory( &pi, 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, &pi))
    {
        // 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等都能达到目的,可根据个人喜好和具体情况采用。

    [相关资源]
    科脑工作室(Kernel Studio):www.kernelstudio.com

  • 相关阅读:
    进程
    Visual Studio Code 使用教程
    C# 多线程中的lock与token模式
    JavaScript中的多态
    简说GC垃圾回收
    C# 简单的SQLHelper
    JavaScript中addEventListener/attachEvent 与内联事件
    JavaScript中事件冒泡与事件捕获
    ASP.Net ScriptManager 与 UpdatePanel
    Nhibernate 使用sql语句查询
  • 原文地址:https://www.cnblogs.com/lzjsky/p/1947888.html
Copyright © 2011-2022 走看看