守护进程的创建

守护进程的创建

守护进程的一般概念

守护进程是挂载在后台的,因此其不因远程终端会话的关闭而结束。
并且其往往用于服务器自检和重启动,其应尽可能简洁。
所以我们得到了如下两个特性:
1.后台运行。不受输入输出和控制终端影响
2.与当前环境隔离。包括未关闭的文件描述符、控制终端、会话、进程组、工作目录和文件创建掩码等等

守护进程创建的流程图

graph TB
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;
}

测试结果与说明

image

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/17133585.html

原文链接: https://www.cnblogs.com/tofu-ran/p/17131658.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    守护进程的创建

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/318909

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月24日 下午3:05
下一篇 2023年2月24日 下午3:05

相关推荐