主要原理:被守护进程B由看门进程A启动(通过B的进程名字B.exe),在启动之后注册进程的退出事件,当B退出时,A捕获退出事件,调用回调函数F,F会再次启动一次B。
Process_Manager_Class.h
#pragma once
//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()
{
ACE_DEBUG((LM_DEBUG,"CProcessManager()\n"));
};
virtual ~CProcessManager()
{
ACE_DEBUG((LM_DEBUG,"~CProcessManager()\n"));
};
// 从配置文件读取进程列表信息
virtual int ReadConfigProcessInfo(char *pFileName);
// 启动进程,并进行进程监控,进程崩溃后,自动重新启动进程
virtual int ProcessMonitor();
private:
vector<string> m_vConfigProcessInfo; // 进程列表信息
};
// 回调事件,程序退出后,执行handle_exit函数
class CProcessExitHandler: public ACE_Event_Handler
{
public:
CProcessExitHandler()
{
ACE_DEBUG((LM_DEBUG,"CProcessExitHandler(%d)\n",this->id_ = ++ increase_));
};
virtual ~CProcessExitHandler()
{
ACE_DEBUG((LM_DEBUG,"~CProcessExitHandler(%d)\n",this->id_));
};
// 程序退出后,执行该函数
virtual int handle_exit(ACE_Process* process);
private:
static int increase_;
int id_;
};
Process_Manager_Class.cpp
//CProcessManager.cpp
#include "Process_Manager_Class.h"
#include <fstream>
using namespace std;
ACE_Process_Manager *g_pPM; // 进程管理
map<string, pid_t> g_mapProcessInfo; // 进程ID管理列表
int
CProcessExitHandler::increase_ = 0;
// 读取进程列表配置文件
int CProcessManager::ReadConfigProcessInfo(char *pFileName)
{
if(NULL == pFileName)
{
ACE_DEBUG((LM_ERROR, ACE_TEXT(": Parameter FileName is null.\n")));
return -1;
}
// 打开进程列表配置文件
ifstream fin(pFileName);
if(!fin)
{
ACE_DEBUG((LM_ERROR, ACE_TEXT(": file open error.[%s]\n"), pFileName));
return -2;
}
// 循环读取进程列表配置文件
while(!fin.eof())
{
string program;
getline(fin,program);
if(0 == program.size() || program[0] == '#')// 去掉回车换行和空白符,跳过注释
{
continue;
}
// 把读取的进程信息放到[进程列表信息]全局变量
m_vConfigProcessInfo.push_back(program);
}
// [进程列表信息]不应该为0
if(m_vConfigProcessInfo.size() == 0)
{
ACE_DEBUG((LM_ERROR, ACE_TEXT(": Process list is null.[%s]\n"), pFileName));
return -3;
}
return 0;
}
// 进程监控
// 根据配置文件启动进程,并注册进程退出时回调函数
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(": ReadConfigProcessInfo[%s] error.\n"), "ProcessManager.conf"));
return -1;
}
// 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(": start a child process failed(%d)%s\n"),
pid, strStartProcess.c_str()));
return -1;
}
ACE_DEBUG((LM_INFO,
ACE_TEXT(": start a child process success(%d)%s\n"),
pid, strStartProcess.c_str()));
// 注册回调(进程退出时,调用该回调)
g_pPM->register_handler(&procExitHandler, pid);
// 添加启动成功的进程到进程ID管理列表
g_mapProcessInfo[strStartProcess] = pid;
ACE_OS::sleep(1);
}
// Run the reactor event loop waiting for events to occur.
ACE_Reactor::instance()->run_reactor_event_loop();
//ACE_Reactor::instance()->end_reactor_event_loop();
return 0;
}
// 进程退出回调函数
// 程序退出后,执行该函数,重新启动进程
int CProcessExitHandler::handle_exit(ACE_Process* process)
{
//等待一段时间再重新启动新进程
ACE_OS::sleep(3);
map<string, pid_t>::iterator itrProcess;
ACE_DEBUG((LM_INFO,
ACE_TEXT(": 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())
{
// 重新启动进程
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(": restart a child process error(%d)%s\n"),
pid, itrProcess->first.c_str()));
return -1;
}
ACE_DEBUG((LM_INFO,
ACE_TEXT(": restart a child process success(%d)%s\n"),
pid, itrProcess->first.c_str()));
// 注册回调(进程退出时,调用该回调),当前对象没有代码负责释放,
//对象自始至终只有一个副本,不会创建更多的CProcessExitHandler
g_pPM->register_handler(this, pid);
// 添加启动成功的进程到进程ID管理列表
itrProcess->second = pid;
break;
}
}
return 0;
}
main.cpp
#ifdef _DEBUG
#pragma comment (lib,"ACEd.lib")
#else
#pragma comment (lib,"ACE.lib")
#endif
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include "Process_Manager_Class.h"
#include <string>
int main(int argc, char *argv[])
{
// Running as a child for test.
if (argc > 1)
{
ACE_OS::sleep(10);
return 0;
}
// set output log file
ACE_OS::setprogname("ProcessManager");
ACE_Date_Time tvTime(ACE_OS::gettimeofday());
string szLogFileName;
szLogFileName = "log.log";
ACE_OSTREAM_TYPE *pLogOutput = new ofstream(szLogFileName.c_str());
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(": ---ProcessManager START---.\n")));
int nRet = 0;
CProcessManager *pProcMng = new CProcessManager();
// 启动进程监控
nRet = pProcMng->ProcessMonitor();
if(nRet != 0)
{
ACE_DEBUG((LM_ERROR, ACE_TEXT(": ---ProcessMonitor Error---\n")));
}
delete pProcMng;
ACE_DEBUG((LM_INFO, ACE_TEXT(": ---ProcessManager STOP---.\n")));
return 0;
}