温馨提示×

linux c++如何写守护进程

小樊
45
2026-09-08 03:17:19
栏目: 编程语言

在 Linux 下用 C/C++ 写守护进程(Daemon),核心是把进程“脱离终端、后台运行”。下面从原理 → 标准写法 → 示例代码 → 进阶建议一步步说明。


一、守护进程的核心步骤

一个标准守护进程通常要做这几件事:

  1. fork 一次,父进程退出(脱离 shell)
  2. setsid 创建新会话(脱离控制终端)
  3. fork 第二次(可选),防止重新获得终端
  4. chdir(“/”) 避免占用挂载目录
  5. umask(0) 重置文件权限掩码
  6. 重定向 stdin/stdout/stderr 到 /dev/null
  7. 正常执行后台逻辑

二、最简可运行示例(C++)

1️⃣ 基础守护进程示例

#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>

void daemonize() {
    pid_t pid = fork();
    if (pid < 0) exit(1);
    if (pid > 0) exit(0);   // 父进程退出

    setsid();               // 创建新会话

    pid = fork();
    if (pid < 0) exit(1);
    if (pid > 0) exit(0);   // 再次 fork,防止重新打开终端

    chdir("/");             // 切换根目录
    umask(0);               // 重置 umask

    // 重定向标准输入输出
    int fd = open("/dev/null", O_RDWR);
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
}

int main() {
    daemonize();

    while (true) {
        // 守护进程逻辑
        sleep(10);
    }
    return 0;
}

编译运行:

g++ daemon.cpp -o daemon
./daemon
ps -ef | grep daemon

三、使用系统函数(推荐)

glibc 提供的 daemon()

#include <unistd.h>

int main() {
    if (daemon(0, 0) < 0) {
        return 1;
    }

    while (true) {
        sleep(10);
    }
}

参数说明:

  • daemon(0, 0)
    • 第一个 0:不 chdir 到 /
    • 第二个 0:不重定向到 /dev/null

⚠️ 注意:daemon() 在部分嵌入式系统中可能不可用。


四、更“专业”的守护进程方案(生产级)

✅ 推荐方式 1:systemd(现代 Linux)

不要自己写守护进程逻辑,让系统管理:

# /etc/systemd/system/mydaemon.service
[Unit]
Description=My Daemon

[Service]
ExecStart=/usr/bin/mydaemon
Restart=always

[Install]
WantedBy=multi-user.target
systemctl start mydaemon
systemctl enable mydaemon

✅ 优点:

  • 自动重启
  • 日志管理(journalctl)
  • 权限/资源控制

✅ 推荐方式 2:fork + systemd(混合)

程序里只做最小 fork,剩下的交给 systemd。


五、日志怎么写?

守护进程不能使用终端,推荐:

  • syslog
  • 文件日志
  • systemd journal

示例(syslog):

#include <syslog.h>

openlog("mydaemon", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "daemon started");

六、常见坑

❌ 忘记 setsid → 仍是终端子进程
❌ 没重定向 stdout → 程序卡死
❌ 在挂载目录中运行 → 无法 umount
❌ 用 while(1) 不处理信号 → 无法优雅退出


七、如果你愿意,我可以帮你:

  • ✅ 写一个完整带信号处理的守护进程
  • ✅ 改成 systemd 服务
  • ✅ 写成 C 风格 / C++ 类封装
  • ✅ 实现 单实例守护进程

你打算用在什么场景?(服务?工具?嵌入式?)

0 踩