我在試下面的代碼。要點如下:
- 第一個分岔的父母等待,直到孩子退出。
- 第一個叉子的孩子做了各種守護進程,然後做了第二個叉子。第二個分支的父(它獲得其子的PID)將PID寫入PID文件,然後退出。
所以用這種方法,前臺進程不會退出,直到後臺進程'PID已被寫入。
(注exit()
和_exit()
之間的差。這個想法是,exit()
確實正常關機,其可包括被C atexit()
功能PID文件或者通過C++析構的或解鎖和刪除。但是_exit()
跳過任何的。這允許後臺進程保持PID文件打開並鎖定(例如使用flock()
),這允許一個「singleton」守護進程。因此,該程序在調用該函數之前應該打開PID文件並打開該文件,如果它是一個C程序,它應該註冊一個atexit()
函數來關閉和刪除PID文件,如果它是一個C++程序,它應該使用RAII風格的類來創建PID文件並在退出時關閉/刪除它。)
int daemon_with_pid(int pid_fd)
{
int fd;
pid_t pid;
pid_t pid_wait;
int stat;
int file_bytes;
char pidfile_buffer[32];
pid = fork();
if (pid < 0) {
perror("daemon fork");
exit(20);
}
if (pid > 0) {
/* We are the parent.
* Wait for child to exit. The child will do a second fork,
* write the PID of the grandchild to the pidfile, then exit.
* We wait for this to avoid race condition on pidfile writing.
* I.e. when we exit, pidfile contents are guaranteed valid. */
for (;;) {
pid_wait = waitpid(pid, &stat, 0);
if (pid_wait == -1 && errno == EINTR)
continue;
if (WIFSTOPPED(stat) || WIFCONTINUED(stat))
continue;
break;
}
if (WIFEXITED(stat)) {
if (WEXITSTATUS(stat) != 0) {
fprintf(stderr, "Error in child process\n");
exit(WEXITSTATUS(stat));
}
_exit(0);
}
_exit(21);
}
/* We are the child. Set up for daemon and then do second fork. */
/* Set current directory to/*/
chdir("/");
/* Redirect STDIN, STDOUT, STDERR to /dev/null */
fd = open("/dev/null", O_RDWR);
if (fd < 0)
_exit(22);
stat = dup2(fd, STDIN_FILENO);
if (stat < 0)
_exit(23);
stat = dup2(fd, STDOUT_FILENO);
if (stat < 0)
_exit(23);
stat = dup2(fd, STDERR_FILENO);
if (stat < 0)
_exit(23);
/* Start a new session for the daemon. */
setsid();
/* Do a second fork */
pid = fork();
if (pid < 0) {
_exit(24);
}
if (pid > 0) {
/* We are the parent in this second fork; child of the first fork.
* Write the PID to the pidfile, then exit. */
if (pid_fd >= 0) {
file_bytes = snprintf(pidfile_buffer, sizeof(pidfile_buffer), "%d\n", pid);
if (file_bytes <= 0)
_exit(25);
stat = ftruncate(pid_fd, 0);
if (stat < 0)
_exit(26);
stat = lseek(pid_fd, 0, SEEK_SET);
if (stat < 0)
_exit(27);
stat = write(pid_fd, pidfile_buffer, file_bytes);
if (stat < file_bytes)
_exit(28);
}
_exit(0);
}
/* We are the child of the second fork; grandchild of the first fork. */
return 0;
}
感謝您的替代解決方案。到目前爲止,我還沒有使用systemd的經驗,或者其他任何選項,所以我會檢查它們。但是請注意,管理其自己的PID文件的守護進程不是*固有的*活躍 - 它只是普遍實現的活躍程度。 –