孤兒進程: 即一個其父進程已經終止的進程。 孤兒進程由 init 進程“收養”,init 進程ID為1,因此被收養的孤兒進程的父進程便更新為1。
孤兒進程組: 一個進程組中的所有進程的父進程要麼是該進程組的一個進程,要麼不是該進程組所在的會話中的進程。 一個進程組不是孤兒進程組的條件是,該組中有一個進程其父進程在屬於同一個會話的另一個組中。
GNU解釋了為什麼會提出孤兒進程組的概念:
When a controlling process terminates, its terminal becomes free and a new session can be established on it. (In fact, another user could log in on the terminal.) This could cause a problem if any processes from the old session are still trying to use that terminal.
To prevent problems, process groups that continue running even after the session leader has terminated are marked as orphaned process groups.
When a process group becomes an orphan, its processes are sent a SIGHUP signal. Ordinarily, this causes the processes to terminate. However, if a program ignores this signal or establishes a handler for it, it can continue running as in the orphan process group even after its controlling process terminates; but it still cannot access the terminal any more.
當一個終端控制進程(即會話首進程)終止後,那麼這個終端可以用來建立一個新的會話。這可能會產生一個問題,原來舊的會話(一個或者多個進程組的集合)中的任一進程可再次訪問這個的終端。為了防止這類問題的產生,於是就有了孤兒進程組的概念。當一個進程組成為孤兒進程組時,posix.1要求向孤兒進程組中處於停止狀態的進程發送SIGHUP(掛起)信號,系統對於這種信號的默認處理是終止進程,然而如果無視這個信號或者另行處理的話那麼這個掛起進程仍可以繼續執行。
以下摘自網絡:
終端的問題涉及幾個概念,那就是進程組,會話,作業,下面會分別進行介紹。會話包含了一系列的進程,這些進程按照不同的執行內容會組織成若干進程組,一個會話內的所有進程都必須是該會話首長進程的後代,這樣就保證了這些進程都是由該會話首長進程直接或者間接開啟的,只有這樣的才能保證這些進程確實是在會話首長進程耳目視線之內的,同時,孤兒進程組不再受到會話首長進程的控制。
作業:
只有一個終端,但是有很多事情要同時做,或者起碼分時做,不能先做完一件事再做另一件,怎麼辦?畢竟啟動一個進程後該進程就會獨占終端啊,畢竟shell會將它設置為前台進程組進程啊。這就是作業的功能,只需要在一個命令後加一個&符號就可以了,比如我要執行x,那麼就敲入:
x &
shell的結果是:
[1] 1234
此處1234是進程的pid,而1則是作業的id,這樣這個x就不占用終端了,shell可以啟動其它的進程或者作業了,比如又啟動了作業2:
[2] 4321
此時想起作業1需要使用一下終端來輸入一些信息了,那麼就使用:fg %1將作業1置於前台(作業1中目前只有一個進程),置於前台的作業如何重新放到後台呢?只需要用SIGSTOP信號停止前台使用終端的進程即可,然後該進程就放開終端的占用了
進程組:一個作業就是一個進程組,單獨的進程可以獨占一個進程組也可以加入同一會話的別的進程組,必須要滿足的條件是,同一進程組的所有進程都要是一個會話的後代。所謂的進程組是為了組織作業或者組織同一類任務的。
控制終端:
一個會話的建立者有權力申請一個控制終端,在該控制終端中可以接受標准輸入,可以發送shell理解的控制快捷鍵,可以創建作業並且使用會話頭進程提供的作業控制功能。控制終端只能由會話頭進程創建,並且控制終端是獨占的,只要有一個進程將一個終端當成了控制終端,別的進程不管它是誰都不能這麼做了,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; //設置session
tty->pgrp = process_group(current);
}
可見別的進程是無權申請控制終端的。
這個控制終端平時給誰用呢?最不容被懷疑的會話首長申請了終端,因為如果連他都值得懷疑的話,後面的屬於他的孩子進程們都值得懷疑了,首長申請的終端就是給這些孩子們用的,首長將這些孩子們分成了若干的進程組,指定一個組為前台進程組,只有這個前台進程組的進程才能使用控制終端。bash一般會作為會話首長存在,bash將為一個執行的命令都創建一個進程組,它在接受一個命令准備執行的時候會將該進程設置為前台進程組,它在接受了命令行後加&的命令時,會創建一個作業,並且將它設定為後台進程組,那麼此時前台是誰呢,是bash自己哦。後台進程不能使用終端,如果使用&執行了內部帶有諸如getchar之類函數的進程,那麼其將會收到SIGTTIN信號,不過可以使用fg命令將這類進程提到前台。
控制進程:
很顯然,首先控制進程是一個會話的首長進程,另外即使是會話首長也只能通過終端來控制別的進程,所謂的控制就是發送信號而不是操作內存之類的,這也是進程間通信的一種方式。因此所謂的控制進程就是申請到控制終端的進程。(作業控制類似)
孤兒進程組:
有孤兒進程,對應的也有孤兒進程組的概念。為何引入這個概念以及這個概念的引入需要OS的實現者作些什麼呢?先看兩個前提,首先,posix用一個session的概念來描述一次用戶的登錄以及該用戶在此次登錄後的操作,然後用作業的概念描述不同操作的內容,最後才用進程的概念描述不同操作中某一個具體的工作;其次,unix最初將所有的進程組織成了樹的形式,這樣就便於追蹤每個進程也便於管理(想想看,人類政治社會也是一個類似樹形結構:君主專制,兩院制等)。有了上述兩個前提事情就很明白了,一切都是為了便於管理,一切都是為了登錄用戶的安全,即此次登錄用戶的作業是不能被下個登錄用戶所控制的,即使它們的用戶名一致也是不行的,因此所謂的孤兒進程組簡單點說就是脫離了創造它的session控制的,離開其session眼線的進程組,unix中怎樣控制進程,怎樣證明是否在自己的眼線內,那就是樹形結構了,只要處於以自己為根的子樹的進程就是自己眼線內的進程,這個進程就是受到保護的,有權操作的,而在別的樹枝上的進程原則上是觸動不得的(又想說說windows的遠程線程創建了,可是說的話還要接著說其復雜的令牌機制,否則windows粉絲不服氣,所以不說了罷),unix中建立進程使用fork,自然地這麼一“叉子”就形成了自己的一個樹枝,當然在自己眼線了,一般對於登錄用戶而言一個會話起始於一次login之後的shell,只要該用戶不logout,在該終端的shell上執行的所有的非守護進程都是該shell的後代進程,因此它們組成一個會話,全部在shell的眼線中,一個會話終止於會話首長的death(注意:進程組的終止與組長進程的終止無關)。現在考慮一下終端上的shell退出後的情景,按照規定,該終端上所有的進程都過繼給了別的進程,大多數情況是init進程,然後緊接著另外一個用戶登錄了這個終端或者知道前一個登錄用戶密鑰的另一個有不好念頭的人登錄了該終端,當然為其啟動的shell創建了一個新的session,由於之前登錄的用戶已退出,現在登錄的用戶由於之前用戶的進程組都成了孤兒進程組,所以它再有惡意也不能控制它們了,那些孤兒進程組中的成員要麼繼續安全的運行,要麼被shell退出時發出的SIGHUP信號殺死。
POSIX的規定是鐵的紀律,而unix或者linux的不管是內核還是shell的實現則是一種遵守紀律的方式,鐵的紀律要求作業控制要以session為基本,就是說不能操作別的session內的進程組,所以類似fg和bg等命令就不能操作孤兒進程,因此如果由於後台進程組由於讀寫終端被SIGSTOP信號停了,而後它又成了孤兒進程組的成員,那怎麼辦?別的session的作業控制命令又不能操作它,即使ps -xj找到了它然後手工發送了SIGCONT,那麼它還是沒法使用終端,這是POSIX的另一個紀律要求的,只有唯一和終端關聯的session中的前台進程組的進程可以使用終端,因此只要有一個shell退出了,最好的辦法就是將其session內的所有的進程都干掉,因此SIGHUP的原意就是如此,但是完全可以忽略這個信號或者自己定義對該信號的反應。POSIX的基本限制就是session的ID是不能設置的,因為它是受保護的基本單位,但是進程組的ID是可以設置的,畢竟它只是區分了不能的作業,最後進程的PID也是不能設置的,因為它是進程的內秉屬性,形成樹形進程結構的關鍵屬性。
POSIX對孤兒進程組的定義:組中沒有一個進程的父進程和自己屬於同一個會話但是不同進程組的。
守護進程:
守護進程需要做幾件事:
1.fork一個子進程:由於bash在執行程序的時候會在fork和exec之間將該程序設置為前台進程組進程,這裡的fork之後不進行如此設置,那麼子進程就會成為後台進程,並且沒有獨占一個進程組,子進程屬於父進程的進程組。
2.調用setsid開啟一個新的會話,開啟一個新的進程組,該進程成為一個新的會話的首長。
3.再次fork一個子進程,這樣可以避免第一次fork時的子進程重新申請控制終端,畢竟它是會話首長。
4.關閉所有文件描述符,特別關閉0,1,2等和終端相關的描述符,因為已經沒有終端了。
5….