Linux--进程间关系和守护进程

版权声明:允许转载,请注明文章出处 https://blog.csdn.net/Vickers_xiaowei/article/details/84396917


本片博客会粘贴部分代码,想要了解更多代码信息,可访问 小编的GitHub关于本篇的代码

进程组/作业/会话的关系

进程组

  • 进程组是一个或多个进程的集合,进程组也有进程组唯一标识(进程组ID就是进程组长的进程ID)。同一个进程组中的进程通常和同一个作业相关联,接受同一终端的各种信号。
  • 进程组长可以创建和销毁一个进程,但是只要进程组中有一个进程存在,那么这个进程就存在,与进程组长是否存在无关。

为了看看这个组长ID我写了下面的代码,这个代码唯一的功能是创建了一个子进程,然后一直等。

#include<stdio.h>
int main()
{
    int pid=fork();
    while(1)
    {
        sleep(1);
    }
    return 0;
}

运行上面段程序,我们打开另外一个终端。查看这个a.out进程信息ps axj|grep a.out

a x j
all job
所有进程 有无终端控制的进程都要列出 与作业相关的进程

在这里插入图片描述

PPID PID PGID SID TTY TPGID STAT UID COMMAND
父进程ID 进程ID 进程组ID 会话ID 终端名称 会话首进程ID 进程状态 用户ID 命令
  • 进程ID=进程的主线程ID
  • 进程组ID=进程组长ID在这里插入图片描述
    当杀掉进程组长,进程组依然存在,子进程依然存在。但是如果ctrl+c发送中断信号,前台进程组就会退出。

作业

  • Shell分前后台控制的是作业(或者进程组),Shell可以运行一个前台作业(或者前台进程组),可以有多个后台作业(或者进程组)。

  • 一般情况下bash(shell)是终端的前台作业,当运行了一个命令,那么这个命令将成为前台作业,bash将成为后台作业,当命令执行完毕之后,bash将成为前台作业。

  • 作业是一个或多个进程的集合。 作业和进程组的区别:前台进程创建的子进程不属于作业,但是属于进程组。
    在这里插入图片描述
    同样是刚刚的程序,在终端1当杀死父进程之后,整个前台作业就挂了,但是这个进程组还存在,因为进程组中的子进程还在,而子进程不属于会话。当前台会话挂了之后,子进程就成了后台进程,可以看到终端0的Shell进程被提到前台。
    在这里插入图片描述

前后台进程组区分及切换方式

  • 在终端输入的所有命令和数据都会给前台进程组。

  • 前台进程组在进程状态之后会有+,后台进程组则没有。在可执行程序后加&,就可以让这个进程组在后台运行,如果是已经运行起来的前台进程组,ctrl+z就可以让这个在前台运行的进程组去后台。
    在这里插入图片描述

  • jobs查看作业,fg+作业号就可以将后台进程组放到前台。bg+作业号,就可以将前台进程组放到后台运行。
    在这里插入图片描述

会话

  • 成功登陆到终端,就开始了一个会话,其实这个会话可以有(也可以没有)一个会话首进程,这个首进程是shell(bash),这个会话首进程也称为控制进程。 会话ID=会话首进程ID。
  • 一个会话=一个终端控制进程(会话首进程,即shell)+一个前台进程组+任意个后台进程组
    在这里插入图片描述

守护进程(精灵进程)

守护进程概念和创建方式

特殊的孤儿进程----->建立新的会话----->关闭描述符------->重新设置当前工作路径------>(设置文件的默认创建权限掩码------->)成功逆袭成为守护进程
1. 后台运行
2. 脱离与终端的关系,脱离原会话,不受原会话和终端的影响

  • daemon函数
int daemon(int nochdir, int noclose);
The  daemon()  function  is for programs wishing to detach themselves from the
controlling terminal and run in the background as system daemons.

nochdir:若其为0时,即可将工作目录修改为根目录。
noclose:若其为空时,输入、输出、以及错误输出重定向到/dev/null.

子进程脱离原会话,称为守护进程

  • setsid函数
    功能:使用其创建一个新的Session,并且成为Session Leader。
 setsid()  creates  a new session if the calling process is not a process group leader.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <fcntl.h>


void daemon_t()
{
    int pid=-1;
    pid=fork();
    if(pid<0)exit(-1);
    else if(pid>0)exit(1);
    //孤儿子进程,非进程组长,setsid创建新会话
    if(setsid()<0)exit(-1);
    //脱离了原会话,成为守护进程,关闭描述符
    chdir("/");//改变当前工作路径,自己成家

    umask(0);
    int fd=open("/dev/null",O_RDWR);//将文件描述符重定向到黑洞文件
    if(fd<0)exit(-1);
    dup2(fd,0);
    dup2(fd,1);
    dup2(fd,2);
//  close(0);
//  close(1);
//  close(2);
}
int main()
{
    daemon_t();
    while(1)
    {
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
控制进程TPGID=-1,没有控制终端进程,这个4759进程就成了守护进程了,它父进程ID、进程ID、和会话ID都是4759。

为什么守护进程应该使用孙子进程?

  • 这里有一个假定,父进程生成守护进程后,还有自己的事要做,它的人生意义并不只是为了生成守护进程。这样,如果父进程fork一次创建了一个守护进程,然后继续做其它事时阻塞了,这时守护进程一直在运行,父进程却没有正常退出。如果守护进程因为正常或非正常原因退出了,就会变成ZOMBIE进程。

  • 如果fork两次呢?父进程先fork出一个儿子进程,儿子进程再fork出孙子进程做为守护进程,然后儿子进程立刻退出,守护进程被init进程接管,这样无论父进程做什么事,无论怎么被阻塞,都与守护进程无关了。所以,fork两次的守护进程很安全,避免了僵尸进程出现的可能性。

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
void mydaemon(void)
{
    umask(0);//调用umask将文件模式创建屏蔽字设置为0.
    pid_t id=fork();//调用fork,创建子进程
    if(id<0){
        perror("fork()");
    }else if(id>0){
        //father
        exit(0);
    }
    setsid();//set new session//调用setsid函数创建一个会话
    signal(SIGCHLD,SIG_IGN);//忽略SIGCHLD信号,子进程退出时不再给父进程发信号。
    pid_t id1=fork();
    if(id1<0){
        perror("fork()");
    }else if(id1>0){
        //father
        exit(0);
    }
    if(chdir("/")<0){
        //将当前工作目录更改为根目录:
        printf("child dir error\n");
        return;
    }
    //关闭不需要的文件描述符,或者重定向到/dev/null中
    close(0);
    int fd0;
    fd0=open("dev/null",O_RDWR);
    dup2(fd0,1);
    dup2(fd0,2);
}
int main()
{
    mydaemon();
    while(1){
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

  • 第一次fork:是为了调用setsid函数,将子进程自成一个独立会话,成为一个进程组,且不受控制终端的控制。

  • 第二次fork:由于当前的子进程为独立会话且为会话组长,独立的进程组,不受控制终端的控制且可打开控制终端,则需再进行一次fork,之后会话sid与id不同,其便不可以打开控制终端。

猜你喜欢

转载自blog.csdn.net/Vickers_xiaowei/article/details/84396917