C++实现进程守护

说明:

基于信号和通过"/proc/"目录判断进程id来监控目标进程状态。
实现了一个简单的进程守护程序。它会启动一个子进程,并监控该子进程的运行状态。如果子进程意外终止,守护程序会重新启动子进程。

代码实现:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <thread>
#include <vector>
#include <cstring>

int g_pid = -1;
bool g_restart = true;
char g_execPath[1024] = "\0";
std::vector<char*> g_argv;

// 创建进程
int CreateProcess()
{
//父子进程中返回子进程的pid,子进程返回0
int pid = fork();
if(pid == -1)
{
printf("fork error\n");
return -1;
}else if(pid == 0){
int ret = execv(g_execPath, g_argv.data());
if(ret < 0)
{
printf("execv : %s(%d)\n", strerror(errno), errno);
return -2;
}
}
return pid;
}

// 通过"/proc/"目录判断进程id是否存在
bool ProcExist(int pid)
{
char proc_path[256];
struct stat file_stat;

snprintf(proc_path, sizeof(proc_path), "/proc/%d", pid);

if (stat(proc_path, &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) {
return true;
} else {
return false;
}
}

// 启动线程
void EntryThread()
{
while(true)
{
if (g_restart && !ProcExist(g_pid))
{
printf("Process(%d) terminated\n", g_pid);
g_pid = CreateProcess();
printf("Process(%d) restarted\n", g_pid);
g_restart = false;
}
usleep(100000); // 100ms
}
return;
}

// 子进程信号处理(SIGCHLD不可靠)
void ChildProcess(int signo)
{
pid_t pid;
int stat;
pid = wait(&stat);
g_restart = true;
//printf("Process %d terminated\n", pid);
//g_pid = CreateProcess();
//printf("Process(%d) restarted\n", g_pid);
}

int main(int argc, char* argv[])
{
// 解析参数(解析子进程路径并透传其他参数)
for(int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "-exec_path")==0 && i+1 < argc)
strcpy(g_execPath, argv[++i]);
else
g_argv.push_back(argv[i]);
}
// 确保参数数组以 nullptr 结尾
g_argv.push_back(nullptr);

// 获取当前路径默认进程名
if(g_execPath[0] == '\0')
{
int len = strlen(argv[0]);
strcpy(g_execPath, argv[0]);
while (len-- > 0) {
if (g_execPath[len] == '/') {
g_execPath[len + 1] = '\0';
break;
}
}
if (len < 0) {
strcpy(g_execPath, "./\0");
}
strcat(g_execPath, "test_exec");
}
//注册子进程退出信号处理函数
signal(SIGCHLD, &ChildProcess);
std::thread th(EntryThread);
th.join();
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!