进程监控模块配置与使用 ------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、配置环境变量
这一步主要是为了大家跨平台使用而设的。
点击计算机 --- 属性 --- 高级系统设置
在”系统变量”中新建变量名 ACE_ROOT, 变量值为 你刚刚解压文件的存放位置比如我的是 D:\Process Monitor\ACE_wrappers
并在 “用户变量”下 新建变量 Path ,值设为 %ACE_ROOT%\lib, 当然,你也可以设为绝对路径,D:\Process Monitor\ACE_wrappers\lib 都是可以的。
这样做的目的是为了,当我们引用动态链接库的时候,VS中就可以不用管了,不然,我们还需要在VS中手动添加.dll,这个也很麻烦。
这两部完成之后,点击确定即可。
3、测试配置环境
从刚刚解压的文件中,D:\Process Monitor\ACE_wrappers\examples (这是我的文件目录)下面,随便拷贝一个工程下来,这里用Logger举例。
拷贝Logger文件夹到其他位置,然后打开工程 Logger_vc10.sln (这里我用的是VS2010),如果大家用的是VS2012请打开Logger_vc11.sln。打开之后,会出现一个解决方案,三个项目。
第一次编译,肯定会不成功。因为我们还没加入.h 和 .lib 文件。即:头文件和库文件
选中某一个项目,右击 ---- 属性 ---- VC++ 目录,在”包含目录“中写上 D:\Process Monitor\ACE_wrappers
在”库目录“中,写上 D:\Process Monitor\ACE_wrappers\lib 。在这里面写有一个好处就是,你下次在重新建立项目的时候,就不用在配置了,配置一次,一劳永逸。它属于全局配置,当然,我们也可以为单个项目进行配置。
如下图所示:
当对单个项目进行配置的时候,需要在 C/C++和链接器中进行配置。这里暂不配置。
此时再编译就OK了。(需要对三个项目分别作上述配置)
4、下面进入正题,使用ACE实现进程监控
参考资料: http://blog.csdn.net/dgyanyong/article/details/12156977/ 使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)
整个项目的大致如下面的框架结构:
我是用的Logger项目,将底下的其他项目剔除掉,然后新建自己的类。
//使用ACE监控启动进程,进程崩溃后自动重启(windows/linux通用)
原理:
监护程序使用子进程的方式启动各个进程,
子进程退出时,监护程序能够得到相应的退出信号,
从而在子进程退出后,在重新启动相应的子进程。
//----------------------------------------------------------
//配置文件ProcessManager.conf格式
//./PROCESS_MANAGER 1
//./PROCESS_MANAGER 2
//----------------------------------------------------------
类似:举例如下
D:\OpenCV_demo\Debug\OpenCV_02 1
D:\OpenCV_demoMultiReadData\Debug\OpenCV_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.\n")));
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]\n"), 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] == '\n')
{
strTemp[strTemp.length() - 1] = 0;
}
if(strTemp.length() == 0)
{
continue;
}
if(strTemp[strTemp.length() - 1] == '\r')
{
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]\n"), 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.\n"), "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\n"),
pid, strStartProcess.c_str()));
return -1;
}
ACE_DEBUG((LM_INFO,
ACE_TEXT("[%N:%l]: start a child process success(%d)%s\n"),
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\n"),
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\n"),
pid, itrProcess->first.c_str()));
return -1;
}
ACE_DEBUG((LM_INFO,
ACE_TEXT("[%N:%l]: restart a child process success(%d)%s\n"),
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---.\n")));
int nRet = 0;
CProcessManager *pProcMng = new CProcessManager();
// 启动进程监控
nRet = pProcMng->ProcessMonitor();
if(nRet != 0)
{
ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: ---ProcessMonitor Error---\n")));
}
delete pProcMng;
ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager STOP---.\n")));
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#
举例如下:
存在的问题:
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,,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 = ;
if (recvcount == )
{
proName = processName[];
proId = processId[];
}
else
{
proName = processName[recvcount - ];
proId = processId[recvcount - ];
}
//先关闭进程,然后重启进程 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 -;
}
//重启之后,进程表ID是会变的,这时需要更新进程列表 g_mapProcessInfo[proName] = pid;
LeaveCriticalSection(&g_csTreadCode);
}
}
return ;
} //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 > )
{
ACE_OS::sleep();
return ;
}
// set output log file
ACE_OS::setprogname("ProcessManagerLog");
ACE_Date_Time tvTime(ACE_OS::gettimeofday());
char szLogFileName[];
memset(szLogFileName, , 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---.\n")));
int nRet = ;
CProcessManager *pProcMng = new CProcessManager();
// 启动进程监控
HANDLE hChild = CreateThread(NULL,,ChildFunc,,,NULL);
HANDLE hChild1 = CreateThread(NULL,,ChildFunc1,,,NULL); nRet = pProcMng->ProcessMonitor();//死循环,执行不到下面 if(nRet != )
{
ACE_DEBUG((LM_ERROR, ACE_TEXT("[%N:%l]: ---ProcessMonitor Error---\n")));
}
delete pProcMng;
ACE_DEBUG((LM_INFO, ACE_TEXT("[%N:%l]: ---ProcessManager STOP---.\n")));
ACE_LOG_MSG->clr_flags(ACE_Log_Msg::OSTREAM); //取消log的输出目的地或格式
delete pLogOutput;
return ;
} DWORD WINAPI ChildFunc(LPVOID p)
{
HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,"ChildEvent");
memset(processName,,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 = ;
if (recvcount == )
{
proName = processName[];
proId = processId[];
}
else
{
proName = processName[recvcount - ];
proId = processId[recvcount - ];
}
//先关闭进程,然后重启进程 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 ;
} DWORD WINAPI ChildFunc1(LPVOID p)
{
Sleep();//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()-; i > ; --i)
{
char c = itrProcess->first[i];
if (c == ' ' || (c >= '' && c <= ''))
{
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 == )
{
recvcount = ;
}
SetEvent(hEvent);
}
}
}
return ;
} //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;
//}
参考文档:
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 - 查找窗口
进程监控模块配置与使用 ------ACE(开源项目)的更多相关文章
- 配置开源项目 SlidingMenu 的问题
最近想研究一下开源项目 SlidingMenu,单是配置项目就花了好长的时间,断断续续的尝试,终于配置成功了,写下来和大家分享一下经验. Step 1:导入依赖的项目和例子 打开项目 File -&g ...
- 开源项目-SlideMenu和actionbarsherlock的配置
SlidingMenu 是github上一个非常优秀的开源库,利用它可以很方便的实现左右侧滑菜单的效果,现在这个基本上应用的标配了,如果一个App没有滑动效果基本上是不可能的,中国人都是本着人无我有, ...
- 盘点 Github 所用到的开源项目
http://www.php100.com/html/it/mobile/2014/0401/6736.html 在致力于开源事业的同时,Github也使用一些非常优秀的开源项目的来打造自己的平台与服 ...
- 【分享】2017 开源中国新增开源项目排行榜 TOP 100
2017 年开源中国社区新增开源项目排行榜 TOP 100 新鲜出炉! 这份榜单根据 2017 年开源中国社区新收录的开源项目的关注度和活跃度整理而来,这份最受关注的 100 款开源项目榜单在一定程度 ...
- 阿里开源项目 druid 相关资料汇总
项目发起人访谈:http://www.iteye.com/magazines/90 github主页:https://github.com/alibaba/druid druid 项目,我想我能用很短 ...
- .Net 开源项目资源大全
伯乐在线已在 GitHub 上发起「DotNet 资源大全中文版」的整理.欢迎扩散.欢迎加入. https://github.com/jobbole/awesome-dotnet-cn (注:下面用 ...
- Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)
下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITableVie ...
- swift开源项目精选
Swift 开源项目精选-v1.0 2016-03-07 22:11 542人阅读 评论(0) 收藏 举报 分类: iOS(55) Swift(4) 目录(?)[+] 转自 http: ...
- 开源项目大全 >> ...
http://www.isenhao.com/xueke/jisuanji/kaiyuan.php 监控系统-Nagios 网络流量监测图形分析工具-Cacti 分布式系统监视-zabbix 系统 ...
随机推荐
- Linux下配置MySQL主从复制
一.环境准备 本次准备两台Linux主机,操作系统都为CentOS6.8, 都安装了相同版本的MySQL.(MySQL5.7). 主从服务器的防火墙都开启了3306端口. 相关信息如下: [主服务器] ...
- MFC中关于CListBox控件添加水平滚动条
首先是设置listbox控件的属性 Horizontal Scroll设为TRUE: 然后添加函数到CUighurRecognitionDlg.cpp(在CUighurRecognitionDlg. ...
- HDU 4426 Palindromic Substring
Palindromic Substring Time Limit: 10000ms Memory Limit: 65536KB This problem will be judged on HDU. ...
- windows和ubuntu14.04双系统设置默认启动项
首先开机或者重启,在启动项选择菜单处记住win7对应的序号,从上至下的序号从0开始计数,我的win7系统选项处于第5个,那么序号就应该是4,记住后,打开ubuntu系统. 2 按下Ctrl+alt+T ...
- 【JavaScript 2—基础知识点】:数据类型
导读:我发现不管是哪一门语言,都会先介绍其发展,语法规则,数据类型,流程控制等.那么,这次,就介绍一下JavaScript中的数据类型,有些看着眼熟,有些不熟.熟的也不是之前认识的,不熟的,也不见得就 ...
- 【C#】穿马甲的流程控制语句
导读:话说当年选择.顺序.循环语句风靡整个VB,今年发现,那几个东西又换了件衣服,跑到了C#里蹦跶.开始,真被这几个穿马甲的吓了一跳,没看出来这是老伙伴.突然有一天,瞥见了脱下新衣的孩子们.哈哈哈哈. ...
- ansible部署
ansible的特性:基于Python语言实现,由paramiko,PyYAML和jinjia2三个关键模块 部署简单,agentless 默认使用ssh协议 (1) 基于秘钥认证方式 ...
- scp命令(基于ssh上传文件等)
(转:http://www.cnblogs.com/hitwtx/archive/2011/11/16/2251254.html) svn 删除所有的 .svn文件 find . -name .svn ...
- [BZOJ1663] [Usaco2006 Open]赶集(spfa最长路)
传送门 按照时间t排序 如果 t[i] + map[i][j] <= t[j],就在i和j之间连一条边 然后spfa找最长路 #include <queue> #include &l ...
- 刷题总结——火柴排队(NOIP2013)
题目: 题目背景 NOIP2013 提高组 Day1 试题 题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间 ...