linux 进程组id 错乱,【Linux】终端,进程组,作业,会话及作业控制
終端
概念
在UNIX系統中,用用戶通過終端登錄系統后得到一一個Shell進程,這個終端成為Shell進程的控制終端 (Controlling Terminal),控制終端是保存在PCB中的信息,而我們知道fork會復制PCB中的信息,因此由Shell進程啟動的其它進程的控制終端也是這個終端。
默認情況 下(沒有重定向),每個進程的標準輸入、標準輸出和標準錯誤輸出都指向控制終端,進程從標準輸入讀也就是讀用戶的鍵盤輸入,進程往標準輸出或標準錯誤輸出寫也就是輸出到顯示示器上。此外 在控制終端輸入一些特殊的控制鍵可以給前臺進程發信號,例如Ctrl-C表 示示SIGINT。
每個進程都可以通過一個特殊的設備文件/dev/tty訪問它的控制終 端。事實上每個終端設備都對應一個不同的設備文件,/dev/tty提供了一一個通用的接口,一個進程要訪問它的控制終端既可以通過/dev/tty也可以通過該終端設備所對應的設備文文件來訪 問。
ttyname函數可以由文件描述符查出對應的文件名,該文件描述符必須指向一個終端設備而不能是任意文件。
下面我們來驗證:
下面是驗證代碼:
得到的結果是:
由結果我們可以看出
文件描述符:0(標準輸入),1(標準輸出),2(標準錯誤)的文件都在同一個終端下。
如果我們重新開一個終端,再次運行上面的代碼,得到結果為:
進程組
概念
每一個進程除了有一個進程ID外,還屬于一個進程組。
進程組是一個或多個進程的集合,通常情況下,他們是在同一作業中結合起來的,同一進程組的個進程接受來自同一終端的各種信號。
每一個進程組有一個唯一的進程ID。
進程組ID是一個正整數,可以使用getpgrp函數返回調用進程的進程組ID
#include
pid_t getpgrp(void);
組長進程
每個進程組都有一個組長進程,組長進程的進程組ID等于其進程ID。
進程組組長可以創建一個進程組,創建進程組中的進程然后種植。只要進程組中還有任意一個進程存在,那么這個進程組就存在。
從進程組的創建到最后一個進程離開的時間去成為進程組的生命周期。
進程組驗證
首先我們編寫驗證進程組的代碼:
在上面的代碼中,我們首先創建兩個進程,一個father父進程,一個child子進程,我們讓father和child首先輸出自己的pid,然后循環輸出自己進程名稱。
結果如下:
由結果我們看出,父進程pid為3306,子進程pid為3307,然后父子進程循環打印father,child。
重新打開一個終端,輸入命令
ps -axj | grep "proc_rela"
首先我介紹一下各個標識的意義。
PID(Process ID 進程 ID號)
Linux系統中總是會分配一個號碼用于在其命名空間中唯一地標識它們,即進程ID號(PID),用fork或者cline產生的每個進程都由內核自動地分配一個新的唯一的PID值
TPGID(顯示前臺進程組)
TGID(Thread Group ID 線程組 ID號)
處于某個線程組(在一個進程中,通過標志CLONE_THREAD來調用clone建立的該進程的不同的執行上下文)中的所有進程都有統一的線程組ID(TGID)
如果進程沒有使用線程,則它的PID和TGID相同
線程組中的”主線程”(Linux中線程也是進程)被稱作”組長(group leader)”,通過clone創建的所有線程的task_struct的group_leader成員,都會指向組長的task_struct。
在Linux系統中,一個線程組中的所有線程使用和該線程組的領頭線程(該組中的第一個輕量級進程)相同的PID,并被存放在tgid成員中。只有線程組的領頭線程的pid成員才會被設置為與tgid相同的值。注意,getpid()系統調用
返回的是當前進程的tgid值而不是pid值。
我們可以這么理解
對于一個多線程的進程來說,它實際上是一個進程組,每個線程在調用getpid()時獲取到的是自己的tgid值,而線程組領頭的那個領頭線程的pid和tgid是相同的
對于獨立進程,即沒有使用線程的進程來說,它只有唯一一個線程,領頭線程,所以它調用getpid()獲取到的值就是它的pid
PGID(Process Group ID 進程組 ID號)
每個進程都會屬于一個進程組(process group),每個進程組中可以包含多個進程。進程組會有一個進程組領導進程 (process group leader),領導進程的PID成為進程組的ID (process group ID, PGID),以識別進程組.
PPID( Parent process ID 父進程 ID號)
PPID是當前進程的父進程的PID
SID(Session ID 會話ID)
STAT(狀態欄)
D 不可中斷 Uninterruptible sleep (usually IO)
R 正在運行,或在隊列中的進程
S 處于休眠狀態
T 停止或被追蹤
Z 僵尸進程
W 進入內存交換(從內核2.6開始無效)
X 死掉的進程
< 高優先級
N 低優先級
L 有些頁被鎖進內存
s 包含子進程
+ 位于后臺的進程組;
l 多線程,克隆線程 multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
得到結果:
下面我們分析一下結果:
由程序輸出結果我們已經得到,父進程的進程ID為3235,子進程的進程ID為3236。
于是我們看到第一個進程PID = 3235,為父進程,他的PGID為3235,就是他本身,即:
父進程就是進程組組長進程。
關于STAT位的意義在上面STAT有提到,所有標志相結合即可。
總結:
程序創建了一個進程,該進程又創建了子進程,于是父進程和子進程構成了一個進程組,進程組的組長為父進程。
那么如果父進程結束,子進程不結束,進程組存在不存在呢?
下面我們修改代碼:
這次,我們讓父進程創建子進程后就退出,當然父進程依然是組長進程,當父進程退出后,子進程依然在進行。
可以看到,子進程還在運行,并且組長進程ID就是父進程ID。
但是,即使子進程繼續運行,我們還是可以在shell輸入,并且ctrl+C鍵不能結束子進程,原因是什么呢?
這就是我下面要介紹的:
作業
Shell分前后臺來控制的不是進程而是作業(Job)或者進程組(Process Group)。一個前臺作業可以由多個進程組成,一個后臺也可以由多個進程組成,Shell可以運行一個前臺作業和任意多個后臺作業,這稱為作業控制。
作業與進程組的區別:
如果作業中的某個進程又創建了子子進程,則子子進程不屬于作業。一旦作業運行行結束,Shell就把自己提到前臺,如果原來的前臺進程還存在(如果這個子進程還沒終止),它自動變為后臺進程組。
shell中運行的是作業,當父進程創建了子進程后,雖然子進程屬于進程組,但是子進程不屬于當前作業 ,所以當父進程退出的時候,當前作業也隨之結束掉了。子進程就到后臺進行。然后當前作業就變成bash,我們可以輸入命令。因為此時子進程在后臺,所以我們給他發送ctrl+C信號,他接收不到。所以無法停止,我是用kill命令結束子進程的。
會話
會話(Session)是一個或多個進程組的集合。
一個會話可以有一個控制終端。這通常是登陸到其上的終端設備(在終端登陸情況下)或偽終端設備(在網絡登陸情況下)。建立與控制終端連接的會話首進程被稱為控制進程。
一個會話中的幾個進程組可被分為一個前臺進程組以及一個或多個后臺進程組。所以一個會話中,應該包括控制進程(會話首進程),一個前臺進程組和任意后臺進程組。
無論何時鍵入終端的終端鍵,都會將中斷信號發送到前臺進程組的所有進程
作業控制
作業控制允許在一個終端上啟動多個作業(進程組),他控制哪一個作業可以訪問該終端以及哪些作業在后臺運行。
如上圖,我們輸入兩個命令,可以看出,輸入第一個命令時:
ps,cat進程同屬于一個進程組,組長為ps,bash,ps,cat三個進程屬于一個會話,Learder是bash。
當輸入第二個命令時,在命令后在&符號,表示該進程在后臺運行,[1]是作業編號,4439是該作業中某一個進程的ID,很明顯,在上例中,4439是cat進程。
作業控制與三個信號
SIGINT(Ctrl + C)——中斷字符
SIGQUIT(Ctrl +\)——退出字符
SIGTSTP(Ctrl + Z)——掛起字符
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的linux 进程组id 错乱,【Linux】终端,进程组,作业,会话及作业控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iPhone 15系列标配USB-C接口
- 下一篇: linux 添加本地源,linux 添加