进程间关系和守护进程
一. 進(jìn)程組/作業(yè)/會(huì)話
1.進(jìn)程組
????每一個(gè)進(jìn)程除了有一個(gè)進(jìn)程ID之外, 還屬于一個(gè)進(jìn)程組. 進(jìn)程是一個(gè)或多個(gè)進(jìn)程的集合. 通常, 它們與同一個(gè)作業(yè)向關(guān)聯(lián), 可以接收來自同一個(gè)終端下的各種命令,信號(hào). 每一個(gè)進(jìn)程組都有唯一的進(jìn)程組 ID. 每一個(gè)進(jìn)程組都可以有一個(gè)組長(zhǎng)進(jìn)程. 組長(zhǎng)進(jìn)程的標(biāo)識(shí)是, 其進(jìn)程組 ID 等于組長(zhǎng)進(jìn)程 ID. 組長(zhǎng)進(jìn)程可以創(chuàng)建一個(gè)進(jìn)程組, 也可以創(chuàng)建該進(jìn)程組中的進(jìn)程, 然后終止.只要該組中有一個(gè)進(jìn)程存在, 則該組就存在, 與該組中的組長(zhǎng)進(jìn)程是否存在沒有任何關(guān)系
2. 相關(guān)接口函數(shù)
????????????????
????其中g(shù)etpgrp 函數(shù)用來返回調(diào)用進(jìn)程的進(jìn)程組 ID, setpid 用來將 pid 進(jìn)程的進(jìn)程組 ID 設(shè)置為 pgid, 如果兩個(gè)參數(shù)值相等, 則由 pid 指定的進(jìn)程將會(huì)變成進(jìn)程組組長(zhǎng). 如果 pid 為 0, 則使用調(diào)用者的進(jìn)程 id. 另外, 如果 pgid 為 0, 則由進(jìn)程 pid 指定的進(jìn)程 id將會(huì)變成進(jìn)程組 id.一個(gè)進(jìn)程只能為自己的子進(jìn)程或者為自己設(shè)定進(jìn)程組ID, 但是當(dāng)這個(gè)函數(shù)的子進(jìn)程已經(jīng)調(diào)用了 exec 之后, 父進(jìn)程就不能再改變子進(jìn)程的組ID了
????在大多數(shù)shell下通常是調(diào)用 fork 后讓父進(jìn)程調(diào)用 setpgid , 同時(shí)也讓子進(jìn)程調(diào)用 setpgid.
????其中 ps 命令常用來顯示進(jìn)程相關(guān)信息, 其中選項(xiàng) a 表示不僅列出當(dāng)前用戶的進(jìn)程, 也列出其他所有用戶進(jìn)程, x 表示不僅列出有控制終端的進(jìn)程, 也列出沒有控制終端的進(jìn)程, j 表示列出與作業(yè)相關(guān)的信息, 同時(shí)在上圖中可以看出當(dāng)我們殺死這個(gè)進(jìn)程組中的組長(zhǎng)時(shí), 此時(shí)該組還是任然存在的(該組中的成員還依舊在). 利用 jobs 命令可以查看后臺(tái)相關(guān)進(jìn)程
3. 作業(yè)
????shell分前臺(tái)和后臺(tái)運(yùn)行的不是進(jìn)程, 而是作業(yè)或者進(jìn)程組. 一個(gè)前臺(tái)作業(yè)可以由多個(gè)進(jìn)程構(gòu)成, 一個(gè)后臺(tái)作業(yè)也可以由多個(gè)進(jìn)程組成, shell可以一次運(yùn)行一個(gè)前臺(tái)作業(yè)和任意多個(gè)后臺(tái)作業(yè), 這就叫做作業(yè)控制.
????作業(yè)和進(jìn)程組的區(qū)別: 在作業(yè)中某個(gè)進(jìn)程創(chuàng)建了一個(gè)子進(jìn)程, 該子進(jìn)程屬于該進(jìn)程組, 但是該子進(jìn)程不屬于這個(gè)作業(yè).一旦作業(yè)結(jié)束, shell就把自己提到前臺(tái), (子進(jìn)程還在, 但是子進(jìn)程不屬于改作業(yè)), 如果原來的前臺(tái)進(jìn)程還在, (如果原來的子進(jìn)程還沒有終止), 它將自動(dòng)成為一個(gè)后臺(tái)進(jìn)程. 此時(shí)我們就可以理解當(dāng)我們?cè)谇芭_(tái)起一個(gè)新作業(yè)時(shí), 此時(shí)shell無法執(zhí)行, 那是因?yàn)閟hell被放到了后臺(tái), 而當(dāng)改作業(yè)退出的時(shí)候, shell就被提到了前臺(tái).
3. 會(huì)話
????會(huì)話是一個(gè)或多個(gè)進(jìn)程組的集合, 一個(gè)會(huì)話可以有一個(gè)控制終端. 這通常是登錄到其上的終端設(shè)備或者是偽終端設(shè)備. 建立與控制終端連接的會(huì)話首進(jìn)程是控制進(jìn)程. 一個(gè)終端下的幾個(gè)進(jìn)程組可以被分為一個(gè)前臺(tái)作業(yè)以及一個(gè)或多個(gè)后臺(tái)作業(yè).所以一個(gè)會(huì)話中應(yīng)該包括一個(gè)控制進(jìn)程, 一個(gè)前臺(tái)進(jìn)程組和多個(gè)后臺(tái)進(jìn)程組
????通過上面的一些解釋, 我們可以得知, 一個(gè)作業(yè)或者一個(gè)進(jìn)程組由多個(gè)進(jìn)程組成, 而一個(gè)會(huì)話則由一個(gè)前臺(tái)進(jìn)程組和多個(gè)后臺(tái)進(jìn)程組構(gòu)成.
(1)會(huì)話相關(guān)接口
????????????????????????????????
????該函數(shù)用于建立一個(gè)新的會(huì)話, 如果調(diào)用函數(shù)的進(jìn)程不是一個(gè)進(jìn)程的組長(zhǎng), 那么就建立新的會(huì)話. 此時(shí)該進(jìn)程會(huì)變成新的會(huì)話首進(jìn)程, 而此時(shí)該進(jìn)程就會(huì)成為新會(huì)話中的唯一的一個(gè)進(jìn)程. 而該進(jìn)程會(huì)成為一個(gè)新進(jìn)程組長(zhǎng), 該進(jìn)程 ID 等于調(diào)用該進(jìn)程的進(jìn)程 ID. 該進(jìn)程沒有控制端, 如果在調(diào)用 setsid 前該進(jìn)程有一個(gè)控制端, 那么原有的這個(gè)控制端將會(huì)變成一個(gè)普通文件不再是控制終端
????????????????????????????????
????查看進(jìn)程的會(huì)話編號(hào)SID, 當(dāng) pid = 0 時(shí), 函數(shù)返回調(diào)用進(jìn)程會(huì)話首進(jìn)程進(jìn)程組 ID
????一個(gè)作業(yè)有多個(gè)進(jìn)程構(gòu)成, 一個(gè)會(huì)話由多個(gè)作業(yè)構(gòu)成, 其中包括一個(gè)前臺(tái)作業(yè)和多個(gè)后臺(tái)作業(yè), 建立一個(gè)會(huì)話, 就是會(huì)建立一個(gè)話首進(jìn)程, 而刪除話首進(jìn)程, 該會(huì)話將會(huì)退出.
(2)相關(guān)命令
???? 1)將一個(gè)作業(yè)放到后臺(tái)去執(zhí)行時(shí), 只需在可執(zhí)行程序后面加一個(gè) & 即可. 例如 sleep 100 | sleep 200 &
???? 2)查看后臺(tái)作業(yè): jobs
???? 3) 將一個(gè)后臺(tái)作業(yè)由前臺(tái)提到后臺(tái) Ctrl + Z, bg 作業(yè)號(hào)即可
4. 作業(yè)控制相關(guān)信號(hào)
???? 后臺(tái)作業(yè)是不能讀取終端輸入的, jobs 命令可以查看后臺(tái)相關(guān)作業(yè). fg 可以將某個(gè)作業(yè)從后臺(tái)提到前臺(tái), 但是此時(shí)如果該作業(yè)是停止?fàn)顟B(tài), 則給作業(yè)發(fā)送一個(gè) SIGCONT 信號(hào)使得該作業(yè)能夠繼續(xù)運(yùn)行. bg 將某個(gè)停止的后臺(tái)作業(yè)在后臺(tái)運(yùn)行, 也需要給作業(yè)發(fā)送一個(gè) SIGCONT 信號(hào). 此時(shí)該作業(yè)就可以在后臺(tái)運(yùn)行了.后臺(tái)作業(yè)不能從終端讀取數(shù)據(jù), 但是后臺(tái)作業(yè)可以往終端寫數(shù)據(jù)
二.守護(hù)進(jìn)程
1. 相關(guān)概念
????守護(hù)進(jìn)程也叫做精靈進(jìn)程, 是運(yùn)行在后臺(tái)的一個(gè)特殊進(jìn)程. 它獨(dú)立于控制終端, 自成進(jìn)程組, 自成會(huì)話, 并且周期性地執(zhí)行某些任務(wù)或者周期性地處理某些發(fā)生的事件. Linux 下大多數(shù)的服務(wù)器就是用守護(hù)進(jìn)程來實(shí)現(xiàn)的.
???? Linux下有一些進(jìn)程沒有控制終端, 不能直接和用戶交互. 其他進(jìn)程都需要用戶登錄或運(yùn)行時(shí)創(chuàng)建, 但是守護(hù)進(jìn)程不受用戶登錄或注銷的影響, 它會(huì)一直運(yùn)行.
????通過 ps 命令查看系統(tǒng)中的進(jìn)程, 其中 PPID 是父進(jìn)程編號(hào), PID 是當(dāng)前進(jìn)程編號(hào), PGID 是進(jìn)程組ID, SID 是會(huì)話 ID, TTY 表示終端名稱, TPGID 表示會(huì)話組ID, STAT 表示進(jìn)程狀態(tài), UID表示用戶ID, COMMAND 表示命令字符串可以看到 凡是 TPGID 為 -1 的都是守護(hù)進(jìn)程, COMMAND 用 [] 括起來的都是內(nèi)核線程, 這些線程都是在內(nèi)核中創(chuàng)建, 沒有用戶代碼, 沒有程序文件以及命令行, 通常以 k 開頭. 守護(hù)進(jìn)程一般以 d 結(jié)尾的名字
2. 守護(hù)進(jìn)程的創(chuàng)建
#include<unitd.h> pid_t setsid(); 調(diào)用成功時(shí)返回創(chuàng)建的會(huì)話ID, 失敗時(shí)返回 -1????該函數(shù)在調(diào)用的時(shí)候必須保證調(diào)用的進(jìn)程不能是進(jìn)程組組長(zhǎng), 為了保證該點(diǎn), 就先 fork 然后再讓子進(jìn)程去執(zhí)行 setsid 即可. 其中在創(chuàng)建會(huì)話時(shí), 子進(jìn)程就會(huì)自成組長(zhǎng), 即子進(jìn)程的 id 就會(huì)成為其組長(zhǎng)的id, 并且該進(jìn)程也會(huì)自成會(huì)話, 即會(huì)話 ID就是該進(jìn)程的 ID, 并且如果當(dāng)前進(jìn)程有一個(gè)會(huì)話終端的時(shí)候, 它將會(huì)失去原有的會(huì)話終端, 即原來的會(huì)話終端還是打開的, 仍然可以讀寫, 但是將會(huì)變成一個(gè)普通文件, 不再是控制終端了.
#include<stdio.h> #include<unistd.h> #include<signal.h> #include<fcntl.h> #include<sys/stat.h> #include<stdlib.h>void mydaemon() {int fd0;pid_t id;struct sigaction sa;//1. 屏蔽umaskumask(0);id = fork();if(id < 0){perror("fork");exit(1);}//2. fork 父進(jìn)程退出, 子進(jìn)程運(yùn)行if(id > 0){exit(0);}if(setsid() < 0){perror("setsid");exit(1);}//3. 初始化sasigemptyset(&sa.sa_mask);sa.sa_handler = SIG_IGN;sa.sa_flags = 0;//4. 對(duì)SIGCHLD信號(hào)忽略, 防止產(chǎn)生僵尸進(jìn)程if(sigaction(SIGCHLD, &sa, NULL) < 0){perror("sigaction");exit(1);}fd0 = open("/dev/null", O_RDWR);close(0);dup2(fd0, 1);dup2(fd0, 2); }int main() {mydaemon();while(1){sleep(1);}return 0; }????????
????關(guān)閉當(dāng)前終端, 打開另外一個(gè)終端時(shí), 繼續(xù)查看, 會(huì)發(fā)現(xiàn)原來的會(huì)話還存在, 于是我們可以得出結(jié)論, 守護(hù)進(jìn)程單獨(dú)成組, 單獨(dú)成回話, 不受控制終端控制
????????
總結(jié)
以上是生活随笔為你收集整理的进程间关系和守护进程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有输卵管堵塞该怎么办较优
- 下一篇: 网络相关基础概念