Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 孤兒進程組與終端會話機制深度解析

編輯:Linux 教學

前言

終端、會話、進程組、前台/後台作業、孤兒進程組——這組概念構成了 Linux 作業控制的核心骨架。本文從 POSIX 定義、內核實現、Shell 行為、守護進程雙重 Fork 技巧、SIGHUP/SIGTTOU/SIGTTIN 信號語意五個維度,系統梳理「誰控制終端、誰能讀寫終端、斷開連接時發生什麼」。

一、核心概念定義

概念定義關鍵屬性
會話一組進程組的集合,由會話首進程(Session Leader)創建setsid() 創建,擁有控制終端權
進程組一組相關進程集合,同一會話內PGID = 組長 PID,setpgid() 設置
前台進程組當前佔用控制終端的進程組唯一,可讀寫終端,接收終端信號
後台進程組非前台進程組讀寫終端將收到 SIGTTIN/SIGTTOU
控制終端會話綁定的終端設備/dev/tty,open() 時 O_NOCTTY 可拒絕
孤兒進程組組內所有進程的父進程「不在同一會話的其他組」會話首進程退出後,其子進程組變孤兒

二、POSIX 孤兒進程組規則

當進程組成為孤兒,且組內有進程處於停止狀態(SIGSTOP/SIGTSTP),內核必須向該組發送 SIGHUP + SIGCONT。
目的:防止停止態進程永久凍結,同時通知它們「控制終端已失去」,讓其選擇退出或忽略信號繼續運行(但無法再訪問終端)。

三、終端登入/斷開全流程

  1. 用戶登入:getty → login → shell,Shell 成為會話首進程,調用 setsid()、打開控制終端(/dev/tty)。
  2. 執行前台命令:Shell fork() 子進程 → setpgid() 設新組 → tcsetpgrp() 將該組設為前台 → exec() 運行程序。Shell 等待(wait())。
  3. 執行後台作業:命令尾加 & → Shell 不 tcsetpgrp(),子進程組留在後台。Shell 提示 [1] 1234(作業號 + PID)。
  4. 作業切換:fg %1 將作業 1 設前台(tcsetpgrp);Ctrl+Z 發 SIGTSTP 停止前台組 → Shell 重獲前台。
  5. 用戶斷開(關閉終端/網絡中斷):
    • 終端驅動檢測掛斷 → 向前台進程組 發 SIGHUP。
    • 會話首進程退出 → 內核將該會話所有進程組標記為孤兒進程組。
    • 孤兒組內停止態進程收到 SIGHUP+SIGCONT。
    • 終端釋放,供下一用戶登入建立新會話。

四、守護進程雙重 Fork 標準範式

void daemonize() {
    // 1. 第一次 fork:父進程退出,子進程成為背景進程(非組長)
    if (fork() != 0) _exit(0);

    // 2. setsid:成為新會話首進程、新進程組組長、無控制終端
    if (setsid() < 0) _exit(1);

    // 3. 第二次 fork:防止會話首進程重新獲得控制終端
    if (fork() != 0) _exit(0);

    // 4. 切換工作目錄、重設 umask、關閉所有 fd
    chdir("/");
    umask(0);
    for (int i = 0; i < maxfd; ++i) close(i);
    open("/dev/null", O_RDWR); // fd 0
    dup(0);                    // fd 1
    dup(0);                    // fd 2
}

為何雙重 Fork?

  1. 首 Fork 確保子進程非進程組長,滿足 setsid() 前提。
  2. setsid() 後進程成為會話首領,**理論上可重新打開控制終端**(若打開終端設備且無 O_NOCTTY)。
  3. 二次 Fork 讓「真正的守護進程」非會話首領,**永久喪失獲得控制終端能力**,徹底脫離終端。

五、關鍵信號語意速查

信號觸發場景默認動作典型處理
SIGHUP控制終端掛斷、會話首進程退出、孤兒組停止態喚醒終止守護進程忽略或重讀配置
SIGINTCtrl+C終止前台程序清理退出
SIGQUITCtrl+\終止+核心轉儲調試用
SIGTSTPCtrl+Z停止Shell 作業控制
SIGTTIN後台進程嘗試讀終端停止fg 切前台或重定向輸入
SIGTTOU後台進程嘗試寫終端(若 TOSTOP 模式)停止fg 切前台或重定向輸出
SIGCONT喚醒停止態進程繼續fg/bg、孤兒組喚醒

六、內核關鍵代碼片段(tty_open)

if (!noctty && current->signal->leader && !current->signal->tty && tty->session == 0) {
    task_lock(current);
    current->signal->tty = tty;           // 綁定控制終端
    task_unlock(current);
    current->signal->tty_old_pgrp = 0;
    tty->session = current->signal->session;
    tty->pgrp = process_group(current);   // 設前台進程組
}

只有會話首領、無控制終端、終端無會話三條件滿足時,才能成為控制終端擁有者。

總結

Linux 作業控制以會話-進程組-前台/後台三層模型,配合控制終端唯一歸屬、孤兒進程組 SIGHUP/SIGCONT 機制、後台訪問終端停止信號,構建出完整的終端多路複用與斷開保護體系。
守護進程雙重 Fork + setsid() + 關閉 fd 是脫離終端的標準範式;理解孤兒進程組規則,能預測 SSH 斷開、screen/tmux 保活、systemd 管理服務等場景的進程生死走向。

Copyright © Windows教程網 All Rights Reserved