守护进程和nuhup、的区别
1. &
运行的进程 VS 守护进程
方式 | 终端关闭后是否存活 | 进程归属 | 典型用途 |
---|---|---|---|
command & | 否(默认),除非 nohup 或 disown | 仍属于当前 Shell | 临时后台任务 |
nohup command & | 是(但仍可能受 SIGTERM 影响) | 仍属于当前用户的会话 | 长时间运行任务 |
setsid command | 是 | 独立于终端 | 守护进程 |
systemd | 是 | 受 systemd 监管 | 服务器服务 |
2. 让进程更接近守护进程
如果只是用 &
,进程仍然是当前 Shell 的子进程,可能在终端关闭时收到 SIGHUP
信号而退出。
(1) 使用 nohup
nohup my_script.sh &
nohup
(No Hang Up)阻止SIGHUP
影响进程,使其在终端关闭后仍运行。- 但进程仍在当前会话,如果用户
logout
,可能仍会被终止。
(2) 使用 disown
my_script.sh & disown
disown
让进程脱离 Shell 的作业控制,即使退出 Shell 也不会终止。- 但进程仍是当前会话的一部分,仍可能因
SIGTERM
退出。
(3) 使用 setsid
让进程完全独立
setsid my_script.sh
setsid
让进程脱离终端,并创建新的会话(Session)。- 不会受
SIGHUP
、终端关闭、Shell 退出影响,更接近真正的守护进程。
(4) 完整的守护进程方式(C 代码示例)
如果要创建真正的 Daemon(守护进程),通常需要:
- 创建新会话 (
setsid()
),脱离控制终端。 - 更改工作目录,避免锁定文件系统。
- 重定向标准输入/输出/错误,避免影响终端。
- 后台运行(fork 退出父进程),确保不会占用 Shell。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
void daemonize() {
pid_t pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
if (pid > 0) { // 让父进程退出,子进程成为孤儿进程
exit(EXIT_SUCCESS);
}
setsid(); // 创建新会话,脱离终端
// 重定向标准输入、标准输出、标准错误
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
while (1) {
sleep(10); // 模拟长期运行的任务
}
}
int main() {
daemonize();
return 0;
}
- 这样进程真正独立,不会因终端关闭而退出。
- 运行后可以用
ps aux | grep my_program
看到它仍在运行。
3. 如何管理守护进程?
如果想要更好的管理方式,可以使用:
systemd
(推荐):写systemd
service 配置,自动管理守护进程。supervisord
:轻量级守护进程管理工具。cron
:用@reboot
让进程开机自启。