fork() 創建子進程,父進程退出 → 子進程成為孤兒進程,由 init 進程收養,脫離終端控制。setsid() 創建新會話,成為會話組長、進程組長,失去控制終端(無法接收 SIGINT/SIGHUP)。fork() 確保進程非會話組長,無法重新獲得控制終端(更嚴格的守護進程模式)。/,避免掛載點無法卸載。umask(0)。/dev/null。#include <iostream>
#include <unistd.h>
using namespace std;
void print_ids() {
cout << "PID=" << getpid() << ", PGID=" << getpgid(0) << endl;
}
int main() {
pid_t pid = fork();
if (pid < 0) { cerr << "fork error" << endl; return 1; }
if (pid > 0) { // 父進程
cout << "Parent exiting..." << endl;
return 0;
}
// 子進程:第一次 fork 後
cout << "--- 1st child ---" << endl; print_ids();
if (setsid() < 0) { cerr << "setsid error" << endl; return 1; }
cout << "--- after setsid ---" << endl; print_ids();
// 可選:二次 fork
pid_t pid2 = fork();
if (pid2 < 0) { cerr << "2nd fork error" << endl; return 1; }
if (pid2 > 0) return 0; // 第一子進程退出
// 第二子進程:真正的守護進程
cout << "--- daemon (2nd child) ---" << endl; print_ids();
chdir("/");
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 守護進程主邏輯
for (int i = 0; i < 5; ++i) {
sleep(20);
cout << "Daemon alive..." << endl; print_ids();
}
return 0;
}
setpgrp() 僅設置進程組 ID;setsid() 創建新會話、新進程組、脫離控制終端,功能更強,單獨使用即可。cout 將失效。實際部署應使用 syslog、文件日誌(openlog/fopen)記錄運行狀態。SIGTERM 優雅關閉,忽略 SIGHUP、SIGPIPE、SIGCHLD(或安裝處理器回收殭屍進程)。生產環境建議使用成熟的進程管理工具,避免手寫守護邏輯:
Type=simple 服務單元,自動守護、重啟、日誌收集。--restart=always 實現守護語義。