ProcessMonitor:一个跨平台的进程监控守护程序

本文最后更新于:2025年11月29日 下午

ProcessMonitor:一个跨平台的进程监控守护程序

作为开发者,我很高兴向大家介绍我开发的一个跨平台进程监控守护程序——ProcessMonitor。这是一个用C++17编写的轻量级但功能强大的工具,用于管理和监控多个子进程的生命周期。

项目背景与设计目标

在日常开发和系统运维中,我们经常需要确保关键服务进程持续运行。传统的手动监控方式效率低下,而现有的进程管理工具要么功能过于复杂,要么无法满足特定的跨平台需求。因此,我们决定开发一个简单易用、功能完备的进程监控解决方案。

主要设计目标:

  • 🎯 跨平台兼容:支持Windows和Linux系统
  • 🔄 自动恢复:进程异常退出时自动重启
  • 📝 配置驱动:通过配置文件灵活管理多个进程
  • 🧹 资源清理:自动清理僵尸进程,避免资源泄漏
  • 📊 状态监控:实时监控进程运行状态
  • 🚀 高性能:低资源占用,高效的事件处理

核心架构解析

1. 配置管理系统

ProcessMonitor使用INI格式的配置文件,支持全局配置和进程级配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ProcessConfig {
std::string name; // 进程名称
std::string path; // 可执行文件路径
std::string working_dir; // 工作目录
std::string args; // 命令行参数
std::map<std::string, std::string> env_vars; // 环境变量
int restart_delay; // 重启延迟时间
int max_restarts; // 最大重启次数
int graceful_timeout; // 优雅关闭超时时间

// 原子变量,确保线程安全
std::atomic<int> restart_count{0};
std::atomic<bool> should_stop{false};
std::atomic<bool> is_running{false};
};

配置文件示例:

1
2
3
4
5
6
7
8
9
10
11
12
[Global]
log_level = INFO
log_file = process.log
check_interval = 2

[Process1]
name = demo
path = /work/ftpd/lsx/demo
working_dir = /work/ftpd/lsx
restart_delay = 3
max_restarts = 5
graceful_timeout = 10

配置加载的核心逻辑在 loadConfig() 方法中实现,它逐行解析配置文件,处理环境变量引用(如 ${VAR}),并验证配置的有效性。

2. 多线程监控模型

ProcessMonitor采用多线程架构,每个被监控的进程都有两个专用线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Process {
private:
std::map<std::string, ProcessConfig> processes_;
std::map<std::string, std::thread> monitor_threads_;
std::map<std::string, std::thread> zombie_cleaner_threads_;
std::atomic<bool> global_stop_{false};

// 平台特定的进程句柄存储
#ifdef _WIN32
std::map<std::string, PROCESS_INFORMATION> process_handles_;
#else
std::map<std::string, pid_t> process_pids_;
#endif
};

监控线程 (monitorProcess) 定期检查进程状态,处理自动重启逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Process::monitorProcess(const std::string &process_name) {
while (!global_stop_) {
// 检查进程状态
bool running = isProcessRunning(process_name);

if (!running && !config.is_running) {
// 检查重启次数限制
if (restart_count < max_restarts || max_restarts == -1) {
if (startProcess(config)) {
config.restart_count++;
config.is_running = true;
}
}
}

// 等待检查间隔
std::this_thread::sleep_for(std::chrono::seconds(check_interval_));
}
}

清理线程 (zombieCleaner) 负责回收已终止的进程资源,防止僵尸进程的产生。

3. 跨平台进程管理

Windows平台实现

Windows版本使用作业对象(Job Object)来管理进程组,确保子进程能够被正确清理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool Process::createWindowsProcess(ProcessConfig &config, PROCESS_INFORMATION &proc_info) {
// 创建进程
BOOL success = CreateProcessA(
resolved_path.c_str(),
const_cast<LPSTR>(command_line.c_str()),
NULL, NULL, FALSE,
CREATE_NEW_PROCESS_GROUP, // 创建新进程组
env_block.empty() ? NULL : LPVOID(env_block.c_str()),
resolved_working_dir.c_str(),
&startup_info, &proc_info
);

// 创建作业对象管理进程组
HANDLE job = CreateJobObject(NULL, NULL);
if (job) {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0};
job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info));
AssignProcessToJobObject(job, proc_info.hProcess);
}

return success;
}

Linux/Unix平台实现

Unix版本使用进程组和信号机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bool Process::createUnixProcess(ProcessConfig &config, pid_t &pid) {
pid = fork();

if (pid == 0) {
// 子进程代码
setsid(); // 创建新的会话,脱离终端控制

// 设置工作目录和环境变量
if (!resolved_working_dir.empty()) {
chdir(resolved_working_dir.c_str());
}
setupEnvironment(config.env_vars);

// 执行目标程序
execv(resolved_path.c_str(), argv.data());
exit(1); // 如果execv失败
}

return pid > 0;
}

4. 优雅关闭机制

ProcessMonitor实现了完善的优雅关闭流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool Process::terminateUnixProcess(pid_t pid, pid_t process_group, int timeout_sec) {
// 先尝试优雅关闭
if (timeout_sec > 0) {
kill(-process_group, SIGTERM); // 发送到整个进程组

// 等待进程自然退出
for (int i = 0; i < timeout_sec * 10; ++i) {
if (!isUnixProcessRunning(pid)) {
return true;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}

// 强制终止
kill(-process_group, SIGKILL);
return true;
}

5. 信号处理与主循环

主程序通过信号处理实现优雅退出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void signalHandler(int signal) {
std::cout << "Received signal: " << signal << ". Shutting down..." << std::endl;
running = false;

if (g_daemon) {
g_daemon->stopAll();
}
}

int main(int argc, char *argv[]) {
// 设置信号处理器
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);

Process daemon;
g_daemon = &daemon;

// 加载配置和启动监控
daemon.loadConfig(config_file);
daemon.startAll();

// 主事件循环
while (running) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}

return 0;
}

关键特性深度解析

1. 线程安全的配置管理

由于配置对象在多个线程间共享,我们使用原子变量和互斥锁确保线程安全:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 原子变量确保计数器和标志的线程安全
std::atomic<int> restart_count{0};
std::atomic<bool> should_stop{false};
std::atomic<bool> is_running{false};

// 访问共享数据时使用互斥锁
std::unique_lock<std::mutex> lock(process_mutex_);
auto it = processes_.find(process_name);
if (it != processes_.end()) {
ProcessConfig &config = it->second;
// 处理配置...
}
lock.unlock();

2. 智能重启策略

重启逻辑考虑了多种边界情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (!running && !is_running) {
int restart_count = config.restart_count;
int max_restarts = config.max_restarts;

if (restart_count < max_restarts || max_restarts == -1) {
log(LogLevel::WARNING,
"Process " + process_name + " is not running. Restarting... (" +
std::to_string(restart_count + 1) + "/" +
(max_restarts == -1 ? "∞" : std::to_string(max_restarts)) + ")");

if (startProcess(config)) {
config.restart_count++;
config.is_running = true;
}
} else {
log(LogLevel::ERROR, "Max restarts reached for: " + process_name);
}
}

3. 环境变量解析引擎

支持环境变量引用和动态解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::map<std::string, std::string> Process::parseEnvVars(const std::string &env_str) {
// 处理 ${VAR} 格式的环境变量引用
size_t var_start;
while ((var_start = value.find("${")) != std::string::npos) {
size_t var_end = value.find("}", var_start);
if (var_end != std::string::npos) {
std::string var_name = value.substr(var_start + 2, var_end - var_start - 2);
const char *var_value = std::getenv(var_name.c_str());
if (var_value) {
value.replace(var_start, var_end - var_start + 1, var_value);
}
}
}
return env_vars;
}

构建与部署

项目使用CMake构建系统,支持交叉编译:

1
2
3
4
5
6
7
# 支持多种目标架构
set(COMPILER_TARGET "x86" CACHE STRING "Target architecture: x86, arm32, arm64")
set(TARGET_TYPE "executable" CACHE STRING "Build target type: executable | static | shared")

# 自动收集源文件
file(GLOB_RECURSE SRC_FILES "${CMAKE_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/*.h")

构建命令示例:

1
2
3
mkdir build && cd build
cmake .. -DCOMPILER_TARGET=arm32 -DTARGET_TYPE=executable
make -j

实际应用场景

ProcessMonitor已经在多个生产环境中稳定运行,主要用于:

  1. 微服务管理:监控多个微服务进程,确保服务高可用
  2. 数据处理流水线:管理数据处理任务的启动和恢复
  3. 嵌入式系统:在资源受限的设备上确保关键进程持续运行
  4. 开发环境:在开发过程中自动重启测试服务

总结

ProcessMonitor项目展示了现代C++在系统编程中的强大能力。通过合理使用原子操作、RAII、多线程和平台抽象,我们实现了一个既高效又可靠的进程监控解决方案。

项目的核心优势在于:

  • 代码清晰:良好的面向对象设计和模块划分
  • 性能优异:低资源占用,高效的线程调度
  • 稳定可靠:完善的错误处理和边界情况处理
  • 易于扩展:模块化设计便于添加新功能

我们欢迎社区贡献,共同完善这个项目。如果你在使用过程中遇到问题或有改进建议,请随时在项目仓库中提交Issue或Pull Request。

*项目地址:GitHub Repository ProcessMonitor URL *

*文档:详细使用文档 *



ProcessMonitor:一个跨平台的进程监控守护程序
https://jinbilianshao.github.io/2025/11/29/ProcessMonitor:一个跨平台的进程监控守护程序/
作者
连思鑫
发布于
2025年11月29日
许可协议