Linux下的进程(四):进程关系 - HeavyYuan/A-CD-Record-Management-System GitHub Wiki

终端登录

systemd-logind
  |
 fork
  |
 \|/
systemd-logind
  |
 exec
  |
 \|/
agetty   打开终端设备,读取用户输入账户信息(即登录界面是由agetty提供的)
  |
 exec    这里没有fork,直接是吧agetty的进程映像**替换**成login的映像
  |
 \|/
login  身份验证
  |
 fork
  |
 \|/
shell(bash)

系统启动后,默认只产生一个agetty进程(和tty1绑定),此时不要在本地登录系统,通过ssh登录后,ps -ef | grep agetty可以看到这个agetty进程

alt + F2-F7可以启动其他的agetty进程

进程关系

一、进程和进程的关系

1个 或 多个进程,形成进程组;一个 或 多个进程组,形成会话

进程组有唯一的进程组ID == 该组组长进程ID

会话有唯一的会话ID == 会话首进程的进程ID

创建会话的进程是该会话的会话首进程(session leader)

二、 进程和终端的关系

一个会话可以有一个控制终端(controlling terminal)(常常指tty或pts)

会话首进程(一般是bash)是控制进程(controlling process),其建立了进程和控制终端的连接(bash的/proc/pid/fd下的文件描述符默认指向终端设备)

会话中的进程组分成(有且只有)一个前台进程组(foreground process group)和一个后台进程组(background process group)

前后台进程组ID不是进程的属性,而是终端的属性,即是终端来判断谁是前~,谁是后~

ps o tpgid,comm查看当前控制终端的进程id(tpgid),即前台进程,其余的都是后台进程

作业控制允许在一个终端上启动多个作业(进程组),它控制哪一个作业可以访问终端(前台进程组),以及哪些作业在后台运行。

作业控制常见手段:

后台运行命令:& 挂起前台进程:CTRL + Z 进程恢复到前台运行:fg %jobnumber

只有前台作业接受终端输入,终端输出可以通过stty tostop来阻止后台作业输出到终端。

ps o tpgid,comm查看当前控制终端的进程id(tpgid),即前台进程,其余的都是后台进程

以下程序,当前子进程中有read操作,当子进程变成后台作业之后,读取报错。

//from apue.3e(orphan3.c)

#include "apue.h"
#include <errno.h>

static void
sig_hup(int signo)
{
    printf("SIGHUP received, pid = %ld\n", (long)getpid());
}

static void
pr_ids(char *name)
{
    printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld\n",
        name, (long)getpid(), (long)getppid(), (long)getpgrp(),
        (long)tcgetpgrp(STDIN_FILENO));
    fflush(stdout);
}

int
main(void)
{
    char    c;
    pid_t   pid;

    pr_ids("parent");
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {   /* parent */
        sleep(5);       /* sleep to let child stop itself */
    } else {            /* child */
        pr_ids("child");
        signal(SIGHUP, sig_hup);    /* establish signal handler */
        kill(getpid(), SIGTSTP);    /* stop ourself */
        pr_ids("child");    /* prints only if we're continued */
        if (read(STDIN_FILENO, &c, 1) != 1)。//读取报错
            printf("read error %d on controlling TTY\n", errno);
    }
    exit(0);
}

三、PS格式输出

ps axo pid,ppid,pgid,sid,tpgid,comm

输出:

进程pid,父进程pid,进程组id,会话组id,当前控制tty的进程id,进程名

当前控制tty的进程id:当前控制终端的进程id,进入bash后,该会话的前台进程组id就是tpgid,如果在该bash下运行一个vim,

可以看到该会话的tpgid就是vim进程id

四、孤儿进程组

父进程已经终止的进程称为孤儿进程(orphan process),这种进程有systemd“收养”

孤儿进程组(orphaned process group):该组中每个成员的父进程都是该组的成员,或者不在该组所在的会话

⚠️ **GitHub.com Fallback** ⚠️