East-Daemon

Daemon

意为守护进程,当我们的服务器运行之后,可能会出现一些问题,比如,被意外kill掉,或者是发生了core dump,如果我们没有任何措施,所有接入的服务都会受到影响,所以我们的服务器可以引入守护进程的方法来提供一些基础的保障。

核心函数如下, 其中main_cb就是我们服务器程序入口,如果我们配置使用守护进程的方式启动程序, 在while循环一开始,
我们通过系统调用fork创建一个子进程, 调用后,这之后的代码就有两个进程在执行,并且父子进程获取的返回值不一样,

  1. 子进程中会返回0,可以借此判断之后的代码是运行在子进程中的
  2. 如果出错则会返回负数,比如系统资源不够,进程数量达到上限等
  3. 其他情况则是在父进程中的case

fork出子进程后,就可以将我们的服务器入口在子进程中执行,父进程可以通过调用waitpid等待子进程结束,这个时候又可以分成两种情况:

  1. 子进程正常结束,那么父进程也可以正常结束,整个程序结束
  2. 子进程异常结束,如被kill掉,那么由于父进程会继续while循环,就可以继续通过fork调用再次创建子进程,将服务器重新恢复。

在恢复子进程之前,我们可以将当前线程挂起一段时间,这个时间可以配置。目的是为了防止进程刚结束,资源还没来得及回收,我们就立刻fork新进程出现问题。

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
static int real_daemon(int argc, char** argv, std::function<int(int argc, char** argv)> main_cb) {
using namespace std::chrono;
ProcessInfoMgr::GetInst()->parent_id = getpid();
ProcessInfoMgr::GetInst()->parent_start_time = duration_cast<seconds>(steady_clock::now().time_since_epoch()).count();

while(true) {
pid_t pid = fork();
//Two process run from here.
if(pid == 0) {
//子进程中返回0
ProcessInfoMgr::GetInst()->main_id = getpid();
ProcessInfoMgr::GetInst()->main_start_time = duration_cast<seconds>(steady_clock::now().time_since_epoch()).count();
ELOG_INFO(g_logger) << "child process start, pid: " << getpid();
return real_start(argc, argv, main_cb);
}else if(pid < 0) {
//错误处理
ELOG_ERROR(g_logger) << "fork failed, result: " << pid << " errno: " << errno << "errstr: " << strerror(errno);
return -1;
}else{
//父进程中返回
int status{0};
waitpid(pid, &status, 0);
if(status) {
ELOG_ERROR(g_logger) << "child process terminated, pid: " << pid
<< " status: " << status;
}else {
//子进程正常退出
ELOG_INFO(g_logger) << "child process finished, pid: " << pid;
break;
}
ProcessInfoMgr::GetInst()->restart_count += 1;
sleep(g_daemon_restart_interval->getValue()); //等待资源释放
}
}
return 0;
}

int start_daemon(int argc, char** argv, std::function<int(int argc, char** argv)> main_cb, bool is_daemon) {
if(!is_daemon) {
return real_start(argc, argv, main_cb);
}
return real_daemon(argc, argv, main_cb);
}

测试结果

非守护进程启动

1
2
elvis     988028  101735  0 23:25 pts/10   00:00:00 ./test_daemon
elvis 988310 987973 0 23:25 pts/9 00:00:00 grep --color=auto test_daemon

守护进程启动

1
2
3
elvis     990241  0.0  0.0   9368  5920 pts/10   S+   23:29   0:00 ./test_daemon 2
elvis 990242 0.0 0.0 12452 4812 pts/10 S+ 23:29 0:00 ./test_daemon 2
elvis 990287 0.0 0.0 4028 2240 pts/9 S+ 23:29 0:00 grep --color=auto test_daemon

当我们kill掉子进程之后,通过log发现sleep 5s后,程序又被拉起

1
2
3
4
kill 99024
elvis 990241 0.0 0.0 9368 6080 pts/10 S+ 23:29 0:00 ./test_daemon 2
elvis 990516 0.0 0.0 12452 4656 pts/10 S+ 23:29 0:00 ./test_daemon 2
elvis 990608 0.0 0.0 4028 2240 pts/9 S+ 23:29 0:00 grep --color=auto test_daemon

对应的log,中间一些log删掉了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2025-08-20 23:29:13     990242  0       [INFO]  [system]        /home/elvis/East/East/src/daemon.cc:40  child process start, pid: 990242
2025-08-20 23:29:13 990242 0 [INFO] [system] /home/elvis/East/East/src/Fiber.cc:49 Main Fiber created, id: 0, thread id: 990242
2025-08-20 23:29:13 990242 0 [INFO] [system] /home/elvis/East/East/src/Fiber.cc:81 Fiber created, id: 1, thread id: 990242, run in scheduler: 0

2025-08-20 23:29:26 990242 3 [INFO] [root] /home/elvis/East/tests/test_daemon.cc:18 OnTimer
2025-08-20 23:29:27 990242 2 [INFO] [system] /home/elvis/East/East/include/Scheduler.h:186 Add new task, type: PSt8functionIFvvEE, task id: 15, thread id: -1
2025-08-20 23:29:27 990242 3 [INFO] [root] /home/elvis/East/tests/test_daemon.cc:18 OnTimer
2025-08-20 23:29:28 990242 2 [INFO] [system] /home/elvis/East/East/include/Scheduler.h:186 Add new task, type: PSt8functionIFvvEE, task id: 16, thread id: -1
2025-08-20 23:29:28 990242 3 [INFO] [root] /home/elvis/East/tests/test_daemon.cc:18 OnTimer
2025-08-20 23:29:29 990241 0 [ERROR] [system] /home/elvis/East/East/src/daemon.cc:51 child process terminated, pid: 990242 status: 15 //killed
2025-08-20 23:29:34 990516 0 [INFO] [system] /home/elvis/East/East/src/daemon.cc:40 child process start, pid: 990516 //restart
2025-08-20 23:29:34 990516 0 [INFO] [system] /home/elvis/East/East/src/Fiber.cc:49 Main Fiber created, id: 0, thread id: 990516
2025-08-20 23:29:34 990516 0 [INFO] [system] /home/elvis/East/East/src/Fiber.cc:81 Fiber created, id: 1, thread id: 990516, run in scheduler: 0
2025-08-20 23:29:34 990516 1 [INFO] [system] /home/elvis/East/East/src/Fiber.cc:81 Fiber created, id: 2, thread id: 990516, run in scheduler: 1
2025-08-20 23:29:35 990516 2 [INFO] [system] /home/elvis/East/East/include/Scheduler.h:186 Add new task, type: PSt8functionIFvvEE, task id: 2, thread id: -1
2025-08-20 23:29:51 990516 2 [INFO] [system] /home/elvis/East/East/include/Scheduler.h:186 Add new task, type: PSt8functionIFvvEE, task id: 18, thread id: -1
2025-08-20 23:29:51 990516 3 [INFO] [root] /home/elvis/East/tests/test_daemon.cc:18 OnTimer
2025-08-20 23:29:52 990516 2 [INFO] [system] /home/elvis/East/East/include/Scheduler.h:186 Add new task, type: PSt8functionIFvvEE, task id: 19, thread id: -1
2025-08-20 23:29:52 990516 3 [INFO] [root] /home/elvis/East/tests/test_daemon.cc:18 OnTimer

常用的linxu命令

这一块,用了几个常用的linxu命令,记录一下。

查看进程

👉 平时要看谁占了很多 CPU/内存 → 用 ps aux –sort=-%cpu 或 ps aux –sort=-%mem。

👉 要看进程父子关系/启动参数 → 用 ps -ef。

1
2
ps -ef  System V 风格,更注重 进程关系(UID、PID、PPID、命令)。
ps aux BSD 风格,更注重 资源使用情况(CPU/MEM 占用等)。

杀死进程

优雅结束:kill PID (默认 SIGTERM)

强制结束:kill -9 PID

按名字结束:pkill 程序名

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2015-2025 Xudong0722
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信