守护进程的创建
守护进程的一般概念
守护进程是挂载在后台的,因此其不因远程终端会话的关闭而结束。
并且其往往用于服务器自检和重启动,其应尽可能简洁。
所以我们得到了如下两个特性:
1.后台运行。不受输入输出和控制终端影响
2.与当前环境隔离。包括未关闭的文件描述符、控制终端、会话、进程组、工作目录和文件创建掩码等等
守护进程创建的流程图
D[远程会话]-->A
A[主进程]-.操作一.->B[子进程]
B-.操作二.->B[子进程]
B-.操作三.->C[孙进程]
C-.操作四.->C
操作一
创建子进程并杀死主进程。子进程变为孤儿进程由Init进程托管
pid_t ret = fork();
if (ret == -1) { return -1; }
if (ret > 0) { exit(0); }
操作二
setsid函数创建新的会话。子进程会成为新的会话组组长。由于会话过程对终端的独占性,新进程组与控制终端脱离。
ret = setsid();
if (ret == -1) { return -2; }
操作三
创建孙进程并杀死子进程。孙进程才是真正的守护进程。
ret = fork();
if (ret == -1) { return -3; }
if (ret > 0) { exit(0); }
操作四
关闭打开的文件描述符
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。
umask(0);
signal(SIGCHLD, SIG_IGN);
测试代码
int switchDaemon();
int main()
{
switchDaemon();
return 0;
}
int switchDaemon() {
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__,getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
pid_t ret = fork();
if (ret == -1) { return -1; }
if (ret > 0) { exit(0); }
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__, getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
sleep(1);
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__, getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
ret = setsid();
if (ret == -1) { return -2; }
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__, getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
ret = fork();
if (ret == -1) { return -3; }
if (ret > 0) { exit(0); }
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__, getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
sleep(1);
printf("% s(% d) :< % s> pid=%d ppid=%d pgid=%d sid=%dn", __FILE__, __LINE__, __FUNCTION__, getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
umask(0);
signal(SIGCHLD, SIG_IGN);
return 1;
}
测试结果与说明
1:main.cpp(25) :< switchDaemon> pid=241719 ppid=237439 pgid=241719 sid=237439
2:main.cpp(29) :< switchDaemon> pid=241720 ppid=241719 pgid=241719 sid=237439
3:main.cpp(31) :< switchDaemon> pid=241720 ppid=1 pgid=241719 sid=237439
4:main.cpp(36) :< switchDaemon> pid=241720 ppid=1 pgid=241720 sid=241720
5:main.cpp(41) :< switchDaemon> pid=241721 ppid=241720 pgid=241720 sid=241720
6:main.cpp(43) :< switchDaemon> pid=241721 ppid=1 pgid=241720 sid=241720
1:远程ssh会话,创建进程,我们叫它“父进程”。父进程的ppid和sid指向会话ssh进程id,pid和pgid均为父进程自己。
2:父进程创建子进程。子进程的ppid和pgid指向pid,sid指向会话
3:杀死父进程。子进程的ppid指向1(被init进程托管),sid指向会话,pgid依旧指向被杀死的父进程,不会自己更新。
4:子进程创建全新的会话。子进程依旧被init进程托管,sid指向子进程自己,pgid指向自己。它成了会话绑定的进程。
5:创建孙进程。孙进程ppid和sid和pgid都指向了子进程。
6:杀死子进程。孙进程其余不变,ppid指向1,被Init进程托管。
原文链接: https://www.cnblogs.com/tofu-ran/p/17131658.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/318909
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!