進(jìn)程的控制
什么是進(jìn)程?
狹義上來說:進(jìn)程是操作系統(tǒng)上運(yùn)行的一個(gè)程序。
廣義上來說:進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng)。它是操作系統(tǒng)動(dòng)態(tài)執(zhí)行的基本單元,在傳統(tǒng)的操作系統(tǒng)中,進(jìn)程既是基本的分配單元,也是基本的執(zhí)行單元。
進(jìn)程控制是進(jìn)程管理中最基本的功能。它用于創(chuàng)建一個(gè)新進(jìn)程,終止一個(gè)已完成的進(jìn)程,或者去終止一個(gè)因出現(xiàn)某事件而使其無法運(yùn)行下去的進(jìn)程,還可負(fù)責(zé)進(jìn)程運(yùn)行中的狀態(tài)轉(zhuǎn)換。
Linux系統(tǒng)上進(jìn)程的幾種狀態(tài):
- 運(yùn)行狀態(tài):進(jìn)程正在運(yùn)行,或者在運(yùn)行隊(duì)列中等待運(yùn)行。
- 可中斷等待狀態(tài):進(jìn)程在等待某個(gè)事件的完成,在等待中不可以被信號(hào)或定時(shí)器喚醒,必須等待直到等待的事情發(fā)生。
- 僵死狀態(tài):進(jìn)程已經(jīng)終止,但是進(jìn)程的描述符還在,直到父進(jìn)程的wait函數(shù)釋放。
-
停止?fàn)顟B(tài):進(jìn)程收到系統(tǒng)發(fā)出的信號(hào)(
SIGSTOPSIFTOPSIGTINSIGTOU)之后停止運(yùn)行或者該進(jìn)程正在被跟蹤(調(diào)試應(yīng)用程序gdb,進(jìn)程處于跟蹤狀態(tài))。
進(jìn)程的創(chuàng)建
進(jìn)程的創(chuàng)建一是操作系統(tǒng)來創(chuàng)建。二是由父進(jìn)程創(chuàng)建。
-
使用
fork函數(shù)來分配一個(gè)新的進(jìn)程。函數(shù) 函數(shù)頭文件 函數(shù)原型 函數(shù)功能 fork#include<sys/types> & #include <unistd.h>pid_t fork(void)創(chuàng)建一個(gè)新的子進(jìn)程,繼承原有進(jìn)程(父進(jìn)程)的很多屬性``(用戶ID 組ID 當(dāng)前工作環(huán)境 等等)vfork#include<sys/types> & #include <unistd.h>pid_t vfork(void)類似fork但是使用vfork時(shí)系統(tǒng)會(huì)讓子進(jìn)程共享父進(jìn)程的地址空間,父進(jìn)程與子進(jìn)程的操作互相可見。函數(shù) 相同 不同 fork都是創(chuàng)建一個(gè)子進(jìn)程占用資源的不同,fork占用較大的系統(tǒng)資源,fork一個(gè)新的進(jìn)程會(huì)將父進(jìn)程的很多都會(huì)復(fù)制,增大了消耗vfork子進(jìn)程完全運(yùn)行在父進(jìn)程的地址空間上,子進(jìn)程對(duì)于父進(jìn)程的改變都變得可見。
| 函數(shù) | 相對(duì)于父進(jìn)程來說 |
|---|---|
fork |
父進(jìn)程與子進(jìn)程運(yùn)行的順序不一定,父進(jìn)程與子進(jìn)程運(yùn)行的時(shí)候,兩個(gè)會(huì)搶系統(tǒng)的調(diào)用時(shí)間。 |
vfork |
子進(jìn)程先比父進(jìn)程運(yùn)行,等子進(jìn)程運(yùn)行完之后,父進(jìn)程再運(yùn)行。 |
創(chuàng)建守護(hù)進(jìn)程
什么是守護(hù)進(jìn)程?這是一段來自維基百科的描述。
-
在一個(gè)多任務(wù)的電腦操作系統(tǒng)中,守護(hù)進(jìn)程(英語:daemon)是一種在后臺(tái)執(zhí)行的電腦程序。此類程序會(huì)被以進(jìn)程的形式初始化。守護(hù)進(jìn)程程序的名稱通常以字母“d”結(jié)尾:例如,syslogd就是指管理系統(tǒng)日志的守護(hù)進(jìn)程。
通常,守護(hù)進(jìn)程沒有任何存在的父進(jìn)程(即PPID=1),且在UNIX系統(tǒng)進(jìn)程層級(jí)中直接位于init之下。守護(hù)進(jìn)程程序通常通過如下方法使自己成為守護(hù)進(jìn)程:對(duì)一個(gè)子進(jìn)程運(yùn)行fork,然后使其父進(jìn)程立即終止,使得這個(gè)子進(jìn)程能在init下運(yùn)行。這種方法通常被稱為“脫殼”。
系統(tǒng)通常在啟動(dòng)時(shí)一同起動(dòng)守護(hù)進(jìn)程。守護(hù)進(jìn)程為對(duì)網(wǎng)絡(luò)請(qǐng)求,硬件活動(dòng)等進(jìn)行響應(yīng),或其他通過某些任務(wù)對(duì)其他應(yīng)用程序的請(qǐng)求進(jìn)行回應(yīng)提供支持。守護(hù)進(jìn)程也能夠?qū)τ布M(jìn)行配置(如在某些Linux系統(tǒng)上的devfsd),運(yùn)行計(jì)劃任務(wù)(例如cron),以及運(yùn)行其他任務(wù)。
Linux創(chuàng)建一個(gè)守護(hù)進(jìn)程創(chuàng)建
孤兒進(jìn)程與僵尸進(jìn)程
-
當(dāng)父進(jìn)程先于子進(jìn)程退出時(shí),子進(jìn)程會(huì)被
init或這systemd接收為子進(jìn)程。這一過程亦被稱為收養(yǎng),雖然有PID為1的系統(tǒng)進(jìn)程當(dāng)做父進(jìn)程,但是創(chuàng)建他的父進(jìn)程已經(jīng)被系統(tǒng)回收了。Ubuntu 18.04 LTS的環(huán)境下時(shí),收養(yǎng)的父進(jìn)程為圖形界面的進(jìn)程。只有進(jìn)入字符界面運(yùn)行時(shí),對(duì)應(yīng)收養(yǎng)的父進(jìn)程才為1 -
創(chuàng)建孤兒進(jìn)程與孤兒進(jìn)程
#include <sys/types.h> #include <unistd.h> #include <sys/wait.h> #include <stdio.h> //孤兒進(jìn)程,父進(jìn)程先于子進(jìn)程退出。 int main(void){ int pid; pid = fork(); if(pid == 0){ printf("I am child process.\n"); sleep(5); //確保子進(jìn)程后于父進(jìn)程退出,子進(jìn)程由系統(tǒng)收養(yǎng)并wait掉。 } if(pid > 0){ printf("I am father process.\n"); sleep(1); } return 0; } #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> #include <stdio.h> //孤兒進(jìn)程,父進(jìn)程先于子進(jìn)程退出。 int main(void){ int pid; pid = fork(); if(pid == 0){ printf("I am child process.\n"); exit(0); } //死循環(huán),父進(jìn)程沒有使用wait函數(shù)等待子進(jìn)程運(yùn)行,沒有人清理將是進(jìn)程。 if(pid > 0){ printf("I am father process.\n"); while(1){} } return 0; }
wait 和 waitpid
-
wait和waitpid原型 作用 pid_t wait(int *statloc); 父進(jìn)程暫停,等待子進(jìn)程結(jié)束 pid_t waitpid(pid_t pid, int *statloc, int options); 父進(jìn)程暫停,等到特定的子進(jìn)程結(jié)束
進(jìn)程的退出
| 正常退出 | 異常退出 |
|---|---|
調(diào)用函數(shù)exit\_exit
|
調(diào)用about函數(shù)或者由系統(tǒng)發(fā)出signal退出。 |
exit()與_ecit()的區(qū)別
| 函數(shù) | 區(qū)別 |
|---|---|
exit() |
調(diào)用該函數(shù)后,系統(tǒng)會(huì)先執(zhí)行一些清除操作,然后返還給內(nèi)核。 |
_exit() |
調(diào)用該函數(shù)后,馬上拋給內(nèi)核。 |
exit與return的區(qū)別
| 區(qū)別 | 操作 |
|---|---|
exit |
exit用于結(jié)束一個(gè)程序 |
return |
return用于函數(shù),返回后回到調(diào)用的上一層函數(shù) |
exit的參數(shù),正常退出參數(shù)為0,異常退出參數(shù)為非零值。
執(zhí)行新的程序
-
父進(jìn)程
fork一個(gè)子進(jìn)程后,使用exec函數(shù)來調(diào)用另外的可執(zhí)行程序代替當(dāng)前進(jìn)程的可執(zhí)行映像。進(jìn)程一旦調(diào)用
exec函數(shù)后,相當(dāng)于將原有的進(jìn)程殺死,只保留進(jìn)程ID,對(duì)于系統(tǒng)而言,同樣的進(jìn)程,執(zhí)行的操作不一樣了。 -
exec函數(shù)家族**int execl(const char path, const char arg, ...
*/ (char ) NULL /);**int execlp(const char file, const char arg, ...
*/ (char ) NULL /);**int execle(const char path, const char arg, ...
*/, (char ) NULL, char * const envp[] /);*int execv(const char path, char const argv[]);
*int execvp(const char file, char const argv[]);
**int execvpe(const char file, char const argv[],
? *char const envp[]);
-
例子:
其他的
-
獲得進(jìn)程ID
getpid獲得進(jìn)程IDgetppid-
設(shè)置用戶和用戶組
-
設(shè)置有效用戶ID和實(shí)際用戶ID
setpid -
設(shè)置實(shí)際組和有效組
setgid
若進(jìn)程具有root權(quán)限,則函數(shù)將實(shí)際用戶ID有效用戶ID設(shè)置為參數(shù)UID。
若進(jìn)程沒有root權(quán)限,但UID為實(shí)際用戶,setuid只將有效用戶ID設(shè)為UID。
-
-
-
改變進(jìn)程的優(yōu)先級(jí)。
nice函數(shù)函數(shù) 原型 作用 nice int nice(int increment) 改變程序的優(yōu)先級(jí) getpriority int getpriority(int which, int who) 獲取文件優(yōu)先級(jí) setpriority int setpriority(int which, int who, int prio) 設(shè)置文件優(yōu)先級(jí)