• 进程监控模块配置与使用 ------ACE(开源项目)


    下面我先从此工程的作用讲起:

    此工程适用于程序异常退出,然后自动重启该程序。对于,系统重启不了该进程,那此程序将返回-1,也无法进行下一步工作。

    下面,先从配置开始讲起:

    参考资料:http://hi.baidu.com/hustor/item/ba85ffba3b84d7ee4fc7fdc0  

    windows下ACE怎样安装与使用说明    (已经很详细)

    但是,为节省大家时间,我已经完成部分工作,大家只需要引用若干文件即可。(光编译估计就需要花费 40min,还得视电脑配置),整个文件大概在1.9G左右。

    具体步骤如下:

    1、请大家到此网站下载压缩包:ACE_wrappers.zip(已经编译完毕),解压到一个合适的位置。

    http://pan.baidu.com/s/1o66wdSY

    2、配置环境变量

    这一步主要是为了大家跨平台使用而设的。

    点击计算机 --- 属性 --- 高级系统设置

    image

    在”系统变量”中新建变量名 ACE_ROOT, 变量值为 你刚刚解压文件的存放位置比如我的是 D:Process MonitorACE_wrappers 

    image

    并在 “用户变量”下 新建变量 Path ,值设为 %ACE_ROOT%lib, 当然,你也可以设为绝对路径,D:Process MonitorACE_wrapperslib 都是可以的。

    这样做的目的是为了,当我们引用动态链接库的时候,VS中就可以不用管了,不然,我们还需要在VS中手动添加.dll,这个也很麻烦。

    这两部完成之后,点击确定即可。

    3、测试配置环境

         从刚刚解压的文件中,D:Process MonitorACE_wrappersexamples (这是我的文件目录)下面,随便拷贝一个工程下来,这里用Logger举例。

         拷贝Logger文件夹到其他位置,然后打开工程 Logger_vc10.sln (这里我用的是VS2010),如果大家用的是VS2012请打开Logger_vc11.sln。打开之后,会出现一个解决方案,三个项目。

         第一次编译,肯定会不成功。因为我们还没加入.h 和 .lib 文件。即:头文件和库文件

    选中某一个项目,右击 ---- 属性 ---- VC++ 目录,在”包含目录“中写上   D:Process MonitorACE_wrappers

    在”库目录“中,写上  D:Process MonitorACE_wrapperslib   。在这里面写有一个好处就是,你下次在重新建立项目的时候,就不用在配置了,配置一次,一劳永逸。它属于全局配置,当然,我们也可以为单个项目进行配置。

    如下图所示:

    image

    当对单个项目进行配置的时候,需要在 C/C++和链接器中进行配置。这里暂不配置。

    image

    此时再编译就OK了。(需要对三个项目分别作上述配置)

    4、下面进入正题,使用ACE实现进程监控

    参考资料: http://blog.csdn.net/dgyanyong/article/details/12156977/    使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)

    整个项目的大致如下面的框架结构:

    image

    我是用的Logger项目,将底下的其他项目剔除掉,然后新建自己的类。

    //使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)

    原理:

    监护程序使用子进程的方式启动各个进程,

    子进程退出时,监护程序能够得到相应的退出信号,

    从而在子进程退出后,在重新启动相应的子进程。

    //----------------------------------------------------------
    //配置文件ProcessManager.conf格式
    //./PROCESS_MANAGER 1
    //./PROCESS_MANAGER 2
    //----------------------------------------------------------

    类似:举例如下

    D:OpenCV_demoDebugOpenCV_02  1
    D:OpenCV_demoMultiReadDataDebugOpenCV_02  2

    .h 文件如下:

    //CProcessManager.h
    #include <stdio.h>
    #include <stdlib.h>
    #include <vector>
    #include <string>
    #include <map>
     
    #include "ace/OS.h"
    #include "ace/streams.h"
    #include "ace/Log_Msg.h"
    #include "ace/Date_Time.h"
    #include "ace/Event_Handler.h"
    #include "ace/Reactor.h"
    #include "ace/Process_Manager.h"
     
    using namespace std;
     
    // 进程监控,进程崩溃后,自动重新启动进程
    class CProcessManager
    {
    public:
        CProcessManager(){};
        virtual ~CProcessManager(){};
        // 从配置文件读取进程列表信息
        virtual int ReadConfigProcessInfo(char *pFileName);
        // 启动进程,并进行进程监控,进程崩溃后,自动重新启动进程
        virtual int ProcessMonitor();
     
    private:
        vector<string> m_vConfigProcessInfo;       // 进程列表信息
    };
     
    // 回调事件,程序退出后,执行handle_exit函数
    class CProcessExitHandler: public ACE_Event_Handler
    {
    public:
        CProcessExitHandler(){};
        virtual ~CProcessExitHandler(){};
        // 程序退出后,执行该函数
        virtual int handle_exit(ACE_Process* process);
    };

    .cpp文件

    //CProcessManager.cpp
     
     
    #include "CProcessManager.h"
     
    ACE_Process_Manager *g_pPM;             // 进程管理
    map<string, pid_t> g_mapProcessInfo;    // 进程ID管理列表
     
    // 读取进程列表配置文件
    int CProcessManager::ReadConfigProcessInfo(char *pFileName)
    {
        char *pTemp = NULL;
        char szTemp[1024];
        string strTemp = "";
        if(NULL == pFileName) 
        {
            ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: Parameter FileName is null.
    ")));
            return -1;
        }
        // 文件格式
        //./PROCESS_MANAGER 1
        //./PROCESS_MANAGER 2
        // 打开进程列表配置文件
        FILE *fp = fopen(pFileName, "r");
        if(NULL == fp)
        {
            ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: file open error.[%s]
    "), pFileName));
            return -2;
        }
        // 循环读取进程列表配置文件
        while(1)
        {
            memset(szTemp, 0, sizeof(szTemp));
            pTemp = fgets(szTemp, sizeof(szTemp), fp);
            if(NULL == pTemp)
            {
                break;
            }
            // 去掉注释
            if(szTemp[0] == '#')
            {
                continue;
            }
            strTemp = szTemp;
            if(strTemp.length() == 0)
            {
                continue;
            }
            // 去掉回车换行
            if(strTemp[strTemp.length() - 1] == '
    ')
            {
                strTemp[strTemp.length() - 1] = 0;
            }
            if(strTemp.length() == 0)
            {
                continue;
            }
            if(strTemp[strTemp.length() - 1] == '
    ')
            {
                strTemp[strTemp.length() - 1] = 0;
            }
            if(strTemp.length() == 0)
            {
                continue;
            }
            // 把读取的进程信息放到[进程列表信息]全局变量
            m_vConfigProcessInfo.push_back(strTemp);
        }
        // 关闭进程列表配置文件
        fclose(fp);
        // [进程列表信息]不应该为0
        if(m_vConfigProcessInfo.size() == 0)
        {
            ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: Process list is null.[%s]
    "), pFileName));
            return -3;
        }
        return 0;
    }
     
    // 进程监控   成功返回0,不成功返回-1.
    // 根据配置文件启动进程,并注册进程.退出时,回调函数  
    int CProcessManager::ProcessMonitor()
    {
        int nRet = 0;
        vector<string>::iterator itrConfig;
        string strStartProcess;
     
        m_vConfigProcessInfo.clear();
     
        // 读取进程列表配置文件
        nRet = ReadConfigProcessInfo("ProcessManager.conf");
        if(nRet != 0)
        {
            ACE_DEBUG((LM_ERROR, 
                ACE_TEXT("[%N:%l]: ReadConfigProcessInfo[%s] error.
    "), "ProcessManager.conf"));
            return -1;
        }
        //实例化拥有100个进程空间的进程管理员(进程管理员为全局变量)
        // Instantiate a process manager with space for 100 processes.
        g_pPM = new ACE_Process_Manager(ACE_Process_Manager::DEFAULT_SIZE, ACE_Reactor::instance());
        CProcessExitHandler procExitHandler;
        // 循环配置进程列表,启动进程
        for(itrConfig = m_vConfigProcessInfo.begin(); itrConfig != m_vConfigProcessInfo.end(); ++itrConfig)
        {
            strStartProcess = *itrConfig;
            // 启动进程
            ACE_Process_Options options;
            options.command_line(strStartProcess.c_str());
            pid_t pid = g_pPM->spawn(options); //创建进程并启动
            // 启动进程失败
            if (pid == ACE_INVALID_PID)
            {
                ACE_DEBUG((LM_ERROR, 
                    ACE_TEXT("[%N:%l]: start a child process fail(%d)%s
    "), 
                    pid, strStartProcess.c_str()));
                return -1;
            }
            ACE_DEBUG((LM_INFO, 
                ACE_TEXT("[%N:%l]: start a child process success(%d)%s
    "), 
                pid, strStartProcess.c_str()));
            // 注册回调(进程退出时,调用该回调) 一直在进行,算是验证吧
            g_pPM->register_handler(&procExitHandler, pid); //有返回值
            // 添加启动成功的进程到进程ID管理列表(哈希结构,键值图,string-int结构)
            g_mapProcessInfo[strStartProcess] = pid;
            ACE_OS::sleep(1);
        }
        //运行反应器模式,一直循环等待事件发生,这个事件就是进程退出的事件,下面的方法一直在等待子进程退出,一退出则执行handle_exit方法。
        // Run the reactor event loop waiting for events to occur.
        ACE_Reactor::instance()->run_reactor_event_loop();//死循环,直到返回-1为止 循环调用它procExitHandler类的方法handle_exit
        //ACE_Reactor::instance()->end_reactor_event_loop();
        return 0;
    }
     
    // 进程退出回调函数,使用的时候,我们只需要注册即可。这个属于函数的覆盖
    // 程序退出后,执行该函数,重新启动进程
    int CProcessExitHandler::handle_exit(ACE_Process* process)
    {
        map<string, pid_t>::iterator itrProcess;
     
        ACE_DEBUG((LM_INFO,
            ACE_TEXT("[%N:%l]: Process %d exited with exit code %d
    "),
            process->getpid (), process->return_value()));
     
        // 循环进程ID管理列表,根据进程ID找到退出的进程,重新启动进程
        for(itrProcess = g_mapProcessInfo.begin(); itrProcess != g_mapProcessInfo.end(); ++itrProcess)
        {
            // 根据进程ID,查找进程名
            if(itrProcess->second == process->getpid()) //second指示进程的id号
            {
                // 重新启动进程
                ACE_Process_Options options;
                options.command_line(itrProcess->first.c_str());
                pid_t pid = g_pPM->spawn(options);
                // 重新启动进程失败
                if (pid == ACE_INVALID_PID)
                {
                    ACE_DEBUG((LM_ERROR, 
                        ACE_TEXT("[%N:%l]: restart a child process fail(%d)%s
    "), 
                        pid, itrProcess->first.c_str()));
                    return -1;
                }
                ACE_DEBUG((LM_INFO, 
                    ACE_TEXT("[%N:%l]: restart a child process success(%d)%s
    "), 
                    pid, itrProcess->first.c_str()));
                // 注册回调(进程退出时,调用该回调)
                g_pPM->register_handler(this, pid); //验证(感觉像是递归,只有成功后才返回,保证程序执行)
                // 添加启动成功的进程到进程ID管理列表
                itrProcess->second = pid;
                break;
            }
        }
        return 0;
    }

    主文件 main()

     
     
    // main.cpp
    #include "CProcessManager.h"
     
    int main(int argc, ACE_TCHAR *argv[])
    {
      // Running as a child for test.
        if (argc > 1)
        {
            ACE_OS::sleep(10);
            return 0;
        }
        // set output log file
        ACE_OS::setprogname("ProcessManagerLog");
        ACE_Date_Time tvTime(ACE_OS::gettimeofday());
        char szLogFileName[256];
        memset(szLogFileName, 0, sizeof(szLogFileName));
        sprintf(szLogFileName, "log/%s_%04d%02d%02d_%02d%02d%02d.log", 
            ACE_OS::getprogname(), 
            (int)tvTime.year(), (int)tvTime.month(),  (int)tvTime.day(), 
            (int)tvTime.hour(), (int)tvTime.minute(), (int)tvTime.second());
     
        ACE_OSTREAM_TYPE *pLogOutput = new ofstream(szLogFileName);
        ACE_LOG_MSG->msg_ostream(pLogOutput, true);
        ACE_LOG_MSG->set_flags(ACE_Log_Msg::OSTREAM);
        // Prepends timestamp and message priority to each message
        ACE_LOG_MSG->set_flags(ACE_Log_Msg::VERBOSE_LITE);
        //ACE_LOG_MSG->clr_flags(ACE_Log_Msg::STDERR);
     
        ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager START---.
    ")));
        int nRet = 0;
        CProcessManager *pProcMng = new CProcessManager();
        // 启动进程监控
        nRet = pProcMng->ProcessMonitor();
        if(nRet != 0)
        {
            ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: ---ProcessMonitor Error---
    ")));
        }
        delete pProcMng;
        ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager STOP---.
    ")));
        ACE_LOG_MSG->clr_flags(ACE_Log_Msg::OSTREAM);
        delete pLogOutput;
        return 0;
    }
     
     
     

    其他内容介绍:

    C++ 网络编程库套件
    Adaptive Communication Environment(自适配通信环境),简称ACE。为一个以C++的

    Template技术所做成的开放源代码的可跨平台的网络应用程序的程序库套件。它提供了

    socket/threading/memory management等多种系统调用的面对对象的wrapper,使C++通信软件

    开发更加简单。
    官方网站
    The ADAPTIVE Communication Environment (ACE)
    相关书籍
    The ACE Programmer's Guide,ISBN 0-201-69971-0
    C++ Network Programming
    Mastering Complexity Using ACE and Patterns,ISBN 0-201-60464-7
    Systematic Reuse with ACE and Frameworks,ISBN 0-201-79525-6
    《C++ Network Programming》就是ACE项目的负责人Schmidt写的,这位老哥以前是华盛

    顿大学的副教授,主要研究领域是软件工程(他写了不少关于pattern的文章和书),现在猫到

    UC Irvine去了。这两本书主要介绍了ACE的使用,也涉及了部份设计方面的内容。第一卷主要

    介绍ACE的基本功能和使用,第二卷则偏重通讯软件中的design pattern。搞通信软件开发的

    兄弟们绝对应该看看此书。另外也有人推荐把ACE作为学习C++的范例来学习,呵呵,这就是个

    人喜好的问题了...总的来说ACE的代码风格还是很不错的--比STL那些天书好看些。

    ACE下载地址:http://download.dre.vanderbilt.edu/

    关于ACE的资料下载:http://download.csdn.net/search?q=adaptive%20communication

    %20environment

    一篇好的帖子:http://blog.csdn.net/dgyanyong/article/details/12156977/
                  使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)
    http://daimojingdeyu.iteye.com/blog/828696  Reactor模式的理解

    http://blog.csdn.net/chexlong/article/details/5886700   Windows 平台上安装测试ACE

    记录
    http://blog.csdn.net/zyysql/article/details/6637920 ace第一课--windows下装ace

    http://hi.baidu.com/hustor/item/ba85ffba3b84d7ee4fc7fdc0   windows下ACE怎样安装与

    使用说明?

    http://blog.csdn.net/chexlong/article/details/5886700           Windows 平台上安装测试ACE记录

    http://www.kuqin.com/ace-2002-12/Part-Two/Chapter-4.htm      ACE线程管理

    资料下载: http://download.csdn.net/search?q=adaptive%20communication%20environment

    ACE实现日志记录:  ACE_Log_Msg 类的使用

    http://blog.csdn.net/cskerrydn/article/details/4645219       

    http://bdxnote.blog.163.com/blog/static/8444235200882053248733/             ACE_Log_Msg日志格式

    这里介绍一个小知识点:如何将文件保存到指定目录   http://zhidao.baidu.com/link?url=wzcs4KtlJRnyU4QrUusDF6SFqs2G4x6JoDDhwbdtiIBC1b4jdEHDV3eMhTDaUDJ5STbwHM4veaOVSbyApXz4yK

        sprintf(szLogFileName, "D:\Process Monitor\Logger\Acceptor-server\log\%s_%04d%02d%02d_%02d%02d%02d.log", 
            ACE_OS::getprogname(), 
            (int)tvTime.year(), (int)tvTime.month(),  (int)tvTime.day(), 
            (int)tvTime.hour(), (int)tvTime.minute(), (int)tvTime.second());

         对于上面的函数,\   第一个为转义字符。然后,假如想指定到某一个目录下,必须要先建立好文件夹,默认不会建立文件夹的。而且,你假如不指定,会直接放在此项目的目录下。

           

    //补充两篇好帖子:

    http://blog.csdn.net/someyuan/article/details/3855491                 ACE_REACTOR框架处理事件              很好的阐释了Rector框架的精髓

    http://bdxnote.blog.163.com/blog/static/8444235200810575055324/           ACE进程Wrapper---ACE_Process用法        

     

         整个项目的下载地址:  http://pan.baidu.com/s/15yDWy   

           注:1)配置文件不支持中文目录。  2)支持C++/C#

             举例如下:

    image

         存在的问题:

         1、无法解决程序卡死的问题,程序卡死对此监控程序来说,进程还是处于运行状态,状态码是正确的。只能解决某个进程突然退出的情况。

         2、监控程序可能比较难以关闭,我们可以通过热启动键打开任务管理器关闭。当然,通过程序自身的关闭按钮也可以。

         3、此程序运行在一台工控机上。对于多机通讯问题,没有做。

        

         此程序的实现原理:其实很简单,就是监控程序作为一个父进程,然后其他进程都是子进程,都是从监控这个进程里面开辟的子进程,当然,这些都是别人帮你弄好了,只要会用即可。

         如果有问题,大家可以留言,相互交流。此程序也是参考别人的,不是本人写的,如有不对的地方请批评指正。

    下面补充一点知识:

     几个函数的使用:

      前天打算开辟一个线程去监视各个子进程的状态,如果进程没反应或者死掉,我们可以通过返回给我们的状态码去判断程序是否死掉。如果死掉了,就去触发另一个线程(用事件去做),让它先关闭进程然后隔个1000ms在打开此进程。

      结果,查了老半天,获得了解决的办法。主要是两个函数的使用: IsHungAppWindow((HWD)hProcess)  和  sendmessagetimeout().

      参考文章:

                  http://wenku.baidu.com/link?url=90tVZzjf_5xkYHc6u32w6TYiM9XJKqP2vUTUZpDkgxNWZSiWCq_eh3E6sLuOSA07tzFKgE6f5b5DJySVuMcIlFWJnW6NgtnE8Pn-ogOopZa

                   进程句柄的获取

    //利用进程ID打开该进程,并获取进程句柄
    
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE,FALSE,itrProcess->second);
    
    bool Isgone = TRUE;
    
    Isgone = IsHungAppWindow((HWND)hProcess); //当句柄无效或句柄所标识的窗体的消息循环是正常的,则返回0,否则返回1,代表挂了

    http://msdn.microsoft.com/zh-cn/vstudio/ms633526(v=vs.80).aspx     IsHungAppWindow function use
    http://bbs.csdn.net/topics/360168583                                               用windows API怎样去监测一个程序是否运行?                                      http://www.cnblogs.com/Joseph/articles/1940149.html                        怎么样判断一个进程出错或未响应        

    http://bbs.csdn.net/topics/90969                                                      如何在程序中判断系统中有进程已经停止响应了

     

    两种使用方法程序如下: (不过,遗憾的是,两种调试都没成功。)

    DWORD WINAPI ChildFunc(LPVOID p)
    {
        HANDLE hEvent = CreateEventW(NULL,FALSE,FALSE,(LPCWSTR)("ChildEvent"));
        memset(processName,0,sizeof(processName));
        InitializeCriticalSection(&g_csTreadCode);
        bool bDone = true;
        while(bDone)
        {
            DWORD dwStatus = WaitForSingleObject(hEvent,INFINITE);
            if (dwStatus == WAIT_OBJECT_0)
            {
                EnterCriticalSection(&g_csTreadCode);
    
                string proName = "";
                int proId = 0;
                if (recvcount == 0)
                {
                   proName = processName[9];
                   proId = processId[9];
                }
                else
                {
                   proName = processName[recvcount - 1];
                   proId = processId[recvcount - 1];
                }
                //先关闭进程,然后重启进程
    
                g_pPM ->terminate(proId);
    
                // 重新启动进程
                ACE_Process_Options options;
                options.command_line(proName.c_str());
                pid_t pid = g_pPM->spawn(options);
                // 重新启动进程失败
                if (pid == ACE_INVALID_PID)
                {
                    return -1;
                }
                //重启之后,进程表ID是会变的,这时需要更新进程列表
    
                g_mapProcessInfo[proName] = pid;
                LeaveCriticalSection(&g_csTreadCode);
            }
        }
        return 0;
    }
    
    //DWORD WINAPI ChildFunc1(LPVOID p)
    //{
    //    HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,(LPCTSTR)("ChildEvent"));
    //
    //    bool bDone = true;
    //    while(bDone)
    //    {
    //        map<string, pid_t>::iterator itrProcess;
    //
    //        // 循环进程ID管理列表,根据进程ID找到退出的进程,重新启动进程
    //        for(itrProcess = g_mapProcessInfo.begin(); itrProcess != g_mapProcessInfo.end(); ++itrProcess)
    //        {
    //            //利用进程ID打开该进程,并获取进程句柄
    //            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,itrProcess->second);
    //
    //            //bool Isgone = TRUE;
    //
    //            //Isgone = IsHungAppWindow((HWND)hProcess); //当句柄无效或句柄所标识的窗体的消息循环是正常的,则返回0,否则返回1,代表挂了
    //
    //            //g_pPM ->terminate(itrProcess->second);
    //            DWORD_PTR  dwResult = 0;
    //            LRESULT lr = ::SendMessageTimeout((HWND)hProcess,WM_NULL,0,0,SMTO_ABORTIFHUNG | SMTO_BLOCK,500,&dwResult);//超时0.5s
    //
    //            if (lr)
    //            {
    //                //还可以响应
    //            }
    //            else
    //            {
    //                processName[recvcount] = itrProcess ->first;
    //                processId[recvcount] = itrProcess ->second;
    //                recvcount++;
    //
    //                if (recvcount == 10)
    //                {
    //                    recvcount = 0;
    //                }
    //                SetEvent(hEvent);
    //            }
    //                
    //        }
    //    }
    //    return 0;
    //}

     

     补充:

    通过别人的指点,demo2,终于可以解决进程死掉,然后重启。

    代码如下:

    // main.cpp
    #include "CProcessManager.h"
    
    int main(int argc, ACE_TCHAR *argv[])
    {
        // Running as a child for test.
        if (argc > 1)
        {
            ACE_OS::sleep(10);
            return 0;
        }
        // set output log file
        ACE_OS::setprogname("ProcessManagerLog");
        ACE_Date_Time tvTime(ACE_OS::gettimeofday());
        char szLogFileName[256];
        memset(szLogFileName, 0, sizeof(szLogFileName));
        sprintf(szLogFileName, "D:\Process Monitor\Logger\Acceptor-server\log\%s_%04d%02d%02d_%02d%02d%02d.log", 
            ACE_OS::getprogname(), 
            (int)tvTime.year(), (int)tvTime.month(),  (int)tvTime.day(), 
            (int)tvTime.hour(), (int)tvTime.minute(), (int)tvTime.second());
    
        ACE_OSTREAM_TYPE *pLogOutput = new ofstream(szLogFileName); //如何让文件输出到指定的文件下
        ACE_LOG_MSG->msg_ostream(pLogOutput, true);
        ACE_LOG_MSG->set_flags(ACE_Log_Msg::OSTREAM);//ostream 设置log的输出目的地或格式
        // Prepends timestamp and message priority to each message
        ACE_LOG_MSG->set_flags(ACE_Log_Msg::VERBOSE_LITE);//verbose_lite
        //ACE_LOG_MSG->clr_flags(ACE_Log_Msg::STDERR);
    
        ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager START---.
    ")));
        int nRet = 0;
        CProcessManager *pProcMng = new CProcessManager();
        // 启动进程监控
        HANDLE hChild = CreateThread(NULL,0,ChildFunc,0,0,NULL);
        HANDLE hChild1 = CreateThread(NULL,0,ChildFunc1,0,0,NULL);
    
        nRet = pProcMng->ProcessMonitor();//死循环,执行不到下面
    
    
        if(nRet != 0)
        {
            ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: ---ProcessMonitor Error---
    ")));
        }
        delete pProcMng;
        ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager STOP---.
    ")));
        ACE_LOG_MSG->clr_flags(ACE_Log_Msg::OSTREAM); //取消log的输出目的地或格式
        delete pLogOutput;
        return 0;
    }
    
    DWORD WINAPI ChildFunc(LPVOID p)
    {
        HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,"ChildEvent");
        memset(processName,0,sizeof(processName));
        InitializeCriticalSection(&g_csTreadCode);
        bool bDone = true;
        while(bDone)
        {
            DWORD dwStatus = WaitForSingleObject(hEvent,INFINITE);
            if (dwStatus == WAIT_OBJECT_0)
            {
                EnterCriticalSection(&g_csTreadCode);
    
                string proName = "";
                int proId = 0;
                if (recvcount == 0)
                {
                    proName = processName[9];
                    proId = processId[9];
                }
                else
                {
                    proName = processName[recvcount - 1];
                    proId = processId[recvcount - 1];
                }
                //先关闭进程,然后重启进程
    
                g_pPM ->terminate(proId);
    
                // 重新启动进程  注:在程序开始的时候,死掉的进程已经加入到进程列表,所以这里不用在重启进程,另一个线程里面会帮我们重启
                //ACE_Process_Options options;
                //options.command_line(proName.c_str());
                //pid_t pid = g_pPM->spawn(options);
                //// 重新启动进程失败
                //if (pid == ACE_INVALID_PID)
                //{
                //    return -1;
                //}
                ////重启之后,进程表ID是会变的,这时需要更新进程列表
                //g_mapProcessInfo[proName] = pid;
                LeaveCriticalSection(&g_csTreadCode);
            }
        }
        return 0;
    }
    
    DWORD WINAPI ChildFunc1(LPVOID p)
    {
        Sleep(500);//50ms 检测一次
        bool bDone = true;
        HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,"ChildEvent");//不要用强制转换,行不通
        while(bDone)
        {    
            map<string, pid_t>::iterator itrProcess;
            // 循环进程ID管理列表,根据进程ID找到退出的进程,重新启动进程
            for(itrProcess = g_mapProcessInfo.begin(); itrProcess != g_mapProcessInfo.end(); ++itrProcess)
            {
                //利用进程ID打开该进程,并获取进程句柄 (一个进程它还有窗口句柄(子句柄),这两者不一样)
                //HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,itrProcess->second);
    
                //先解析得到窗体名
                string str = "";
                for (int i = itrProcess->first.size()-2; i > 0 ; --i)
                {
                    char c = itrProcess->first[i];
                    if (c == ' ' ||  (c >= '0' && c <= '9'))
                    {
                        continue;
                    }
                    if (c != '\' )
                    {
                        str += c;
                    }
                    if (c == '\')
                    {
                        break;
                    }
                }
                string s(str.rbegin(),str.rend());//反转
                HWND hProcess = FindWindow(NULL,s.c_str());
                
                //cout << s << endl;
                bool Isgone = TRUE;
    
                Isgone = IsHungAppWindow(hProcess); //当句柄无效或句柄所标识的窗体的消息循环是正常的,则返回0,否则返回1,代表挂了
    
                if (Isgone)
                {
                    processName[recvcount] = itrProcess ->first;
                    processId[recvcount] = itrProcess ->second;
                    recvcount++;
    
                    if (recvcount == 10)
                    {
                        recvcount = 0;
                    }
                    SetEvent(hEvent);            
                }        
            }
        }
        return 0;
    }
    
    
    
    //DWORD WINAPI ChildFunc1(LPVOID p)
    //{
    //    bool bDone = true;
    //    while(bDone)
    //    {
    //        map<string, pid_t>::iterator itrProcess;
    //
    //        // 循环进程ID管理列表,根据进程ID找到退出的进程,重新启动进程
    //        for(itrProcess = g_mapProcessInfo.begin(); itrProcess != g_mapProcessInfo.end(); ++itrProcess)
    //        {
    //            //利用进程ID打开该进程,并获取进程句柄
    //            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,itrProcess->second);
    //            DWORD_PTR  dwResult = 0;
    //            LRESULT lr = ::SendMessageTimeout((HWND)hProcess,WM_NULL,0,0,SMTO_ABORTIFHUNG | SMTO_BLOCK,1000,&dwResult);//超时0.5s
    //
    //            if (lr)
    //            {
    //                //还可以响应
    //            }
    //            else
    //            {
    //                InitializeCriticalSection(&g_csTreadCode);
    //                EnterCriticalSection(&g_csTreadCode);
    //
    //                //先关闭进程,然后重启进程
    //                g_pPM ->terminate(itrProcess->second);
    //
    //                // 重新启动进程
    //                ACE_Process_Options options;
    //                options.command_line(itrProcess->first.c_str());
    //                pid_t pid = g_pPM->spawn(options);
    //                // 重新启动进程失败
    //                if (pid == ACE_INVALID_PID)
    //                {
    //                    return -1;
    //                }
    //                //重启之后,进程表ID是会变的,这时需要更新进程列表
    //                g_mapProcessInfo[itrProcess->first] = pid;
    //                LeaveCriticalSection(&g_csTreadCode);
    //            }
    //
    //        }
    //    }
    //    return 0;
    //}
    View Code

     参考文档:

    http://blog.csdn.net/ddkxddkx/article/details/6332268     c++ string 实现逆序

    http://blog.csdn.net/coolszy/article/details/5523486    FindWindow用法

    http://www.cnblogs.com/del/archive/2008/02/28/1085432.html    

    WinAPI: FindWindow、FindWindowEx - 查找窗口

      

          

  • 相关阅读:
    C#中任意类型数据转成JSON格式
    数据库用户映射到SQL Server登录名
    浅述WinForm多线程编程与Control.Invoke的应用
    Git错误一例
    提高VS2010/VS2012编译速度
    给有兴趣、有责任要讲课、分享的朋友推荐两本书
    中国剩余定理
    中国剩余定理
    洛谷1546 最短网路
    洛谷1111 修复公路
  • 原文地址:https://www.cnblogs.com/zhuxuekui/p/3975309.html
Copyright © 2020-2023  润新知