ps網(wǎng)站輪播圖怎么做app軟件推廣平臺
一、進程的概述
????????可執(zhí)行程序運行起來后(沒有結(jié)束之前),它就成為了一個進程。程序是存放在存儲介質(zhì)上的一個可執(zhí)行文件,而進程是程序執(zhí)行的過程。進程的狀態(tài)是變化的,其包括進程的創(chuàng)建、調(diào)度和消亡。程序是靜態(tài)的,進程是動態(tài)的。
1、程序和進程的區(qū)別
????????程序 靜態(tài)的 占磁盤空間(存放在存儲介質(zhì)上的一個可執(zhí)行文件)
????????進程 動態(tài)的 (調(diào)度、執(zhí)行、消亡),占內(nèi)存空間。(進程是程序執(zhí)行到結(jié)束間的這個過 程)
?2、單道和多道程序設(shè)計
????????單道程序設(shè)計 所有進程一個一個排隊執(zhí)行。若A阻塞,B只能等待,即使CPU處于空閑狀 態(tài)。這種模型在系統(tǒng)資源利用上及其不合理,大部分已被淘汰了。
????????多道程序設(shè)計 在計算機內(nèi)存中同時存放幾道相互獨立的程序,它們在管理程序控制之 下,相互穿插的運行。當(dāng)下常見CPU為納秒級,由于人眼的反應(yīng)速度是毫秒級,所以看似同時在運行。
而多道程序設(shè)計必須有硬件基礎(chǔ)作為保證。時鐘中斷(強制讓進程讓出cpu資源)即為多道程序設(shè)計模型的理論基礎(chǔ)。
3、并行和并發(fā)的區(qū)別
????????并行(微觀)和并發(fā)(宏觀)都是多個任務(wù)同時執(zhí)行(多道程序)。
????????并行(parallel):指在同一時刻,有多條指令在多個處理器上同時執(zhí)行(微觀上同時執(zhí)行)(多核)
????????并發(fā)(concurrency):指在同一時刻只能有一條指令執(zhí)行,但多個進程指令被快速的輪換執(zhí) 行,使得在宏觀上具有多個進程同時執(zhí)行的效果,但在微觀上并不是同時執(zhí)行的,只是把時 間分成若干段,使多個進程快速交替的執(zhí)行(單核 )
?4、進程控制塊(PCB)
????????進程運行時,內(nèi)核為每個進程分配一個PCB(進程控制塊),維護進程相關(guān)的信 息,Linux內(nèi)核的進程控制塊是task_struct結(jié)構(gòu)體。 PCB存在于進程的內(nèi)核空間里面。系統(tǒng)會為每一個進程分配一個進程ID,其類型為pid_t(非負整數(shù)) ,進程的狀態(tài),有就緒、運行、掛起、停止等狀態(tài)。進程狀態(tài)切換時需要保存和恢復(fù)的一些CPU寄存器。進程是系統(tǒng)分配資源的基本單位。
5、進程的狀態(tài)
進程的三大狀態(tài):就緒態(tài)、執(zhí)行態(tài)、等待態(tài)
- 就緒態(tài):執(zhí)行條件全部滿足,等待CPU的執(zhí)行調(diào)度
- 執(zhí)行(運行)態(tài):正在被CPU調(diào)度執(zhí)行
- 等待態(tài):不具備CPU調(diào)度執(zhí)行的執(zhí)行條件,等待條件滿足。?
ps命令查看進程信息:?
選項 | 含義 |
-a | 顯示終端上的所有進程,包括其他用戶的進 程 |
-u | 顯示進程的詳細狀態(tài) |
-x | 顯示沒有控制終端的進程 |
-w | 顯示加寬,以便顯示更多的信息 |
-r | 只顯示正在運行的進程 |
查看進程狀態(tài):ps -aux?
?stat中的參數(shù)意義如下:
以樹狀顯示進程:pstree
?二、進程號PID
????????每個進程都由一個進程號來標識,其類型為 pid_t(整型),進程號的范圍:0~32767。 進程號總是唯一的,但進程號可以重用。當(dāng)一個進程終止后,其進程號就可以再次使用 。
- 進程號(PID): 標識進程的一個非負整型數(shù)
- 父進程號(PPID):父進程號
- 進程組號(PGID): 進程組是一個或多個進程的集合。?
1、獲取進程號的函數(shù)?
頭文件:
#include<sys/type.h>
#include<unistd.h>
函數(shù):
pid_t getpid(void); ?
功能: 獲取本進程號(PID)
參數(shù): 無
返回值: 本進程號?
?2、獲取父進程的ID
#include<sys/type.h>
#include<unistd.h>
pid_t getppid(void);
功能: 獲取調(diào)用此函數(shù)的進程的父進程號(PPID)
參數(shù): 無
返回值: 調(diào)用此函數(shù)的進程的父進程號(PPID)
3、獲取進程組的ID
#include<sys/type.h>
#include<unistd.h>
pid_t getpgid(pid_t pid);
功能: 獲取進程組號(PGID)
參數(shù): pid:進程號
返回值: 參數(shù)為 0 時返回當(dāng)前進程組號,否則返回參數(shù)指定的進程的進程組號 ?
查看父子進程號:ps -ef?
?查看所有進程號:ps -ajx
getchar();防止進程結(jié)束。?
三、 fork創(chuàng)建進程
1、fork函數(shù)
????????系統(tǒng)允許一個進程創(chuàng)建新進程,新進程即為子進程,子進程還可以創(chuàng)建新的子進程,形成進 程樹結(jié)構(gòu)模型。
#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);
功能: 用于從一個已存在的進程中創(chuàng)建一個新進程,新進程稱為子進程,原進程稱為父進程。
參數(shù): 無
返回值: 成功:子進程中返回 0,父進程中返回子進程 ID。pid_t,為整型。 失敗:返回-1。
失敗的兩個主要原因:
????????1)當(dāng)前的進程數(shù)已經(jīng)達到了系統(tǒng)規(guī)定的上限,這時 errno 的值被設(shè)置為 EAGAIN。
????????2)系統(tǒng)內(nèi)存不足,這時 errno 的值被設(shè)置為 ENOMEM?
2、fork出來的子進程和父進程之間的關(guān)系?
?????????使用fork函數(shù)得到的子進程是父進程的一個復(fù)制品,它從父進程處繼承了整個進程的地址空間。 地址空間: 包括進程上下文、進程堆棧、打開的文件描述符、信號控制設(shè)定、進程優(yōu) 先級、進程組號等。 子進程所獨有的只有它的進程號,計時器等。因此,使用fork函數(shù)的代價是很大的 。
????????父子進程 從fork后開始繼續(xù)執(zhí)行。父子進程是同時運行,空間獨立,子進程復(fù)制父進程的所有空間,誰先運行不確定。?
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{//創(chuàng)建子進程pid_t pid=fork();if(pid<0){perror("創(chuàng)建失敗\n");}else if(pid==0){printf("%d為子進程\n",getpid());}else if(pid>0){printf("%d為父進程\n",getpid());}getchar();return 0;
}
3、子進程 復(fù)制 父進程的資源(各自獨立)
4、父子進程同時運行
5、父進程 給子進程 足夠的準備時間時?
?四、特殊的進程
????????孤兒進程、僵尸進程、守護進程。?
1、孤兒進程(無危害)
????????父進程先結(jié)束、子進程就是孤兒進程,會被1號進程接管(1號進程負責(zé)給子進程回收資 源)
終止子進程:?
?2、僵尸進程(有害)
????????子進程結(jié)束,父進程沒有回收子進程資源(PCB),子進程就是僵尸進程。?
當(dāng)父進程結(jié)束后,僵尸進程的資源被回收。?
?3、守護進程
????????守護進程 是脫離終端的 孤兒進程。在后臺運行。為特殊服務(wù)存在的。(一般用于服務(wù)器)
五、父進程回收子進程的資源
????????在每個進程退出的時候,內(nèi)核釋放該進程所有的資源、包括打開的文件、占用的內(nèi)存等。但 是仍然為其保留一定的信息,這些信息主要主要指進程控制塊PCB的信息(包括進程號、退 出狀態(tài)、運行時間等)
????????父進程可以通過調(diào)用wait或waitpid得到它的退出狀態(tài)同時徹底清除掉這個進程。 wait()和 waitpid()函數(shù)的功能一樣,區(qū)別在于,wait()函數(shù)會阻塞,waitpid()可以設(shè)置不阻塞。注意:一次wait或waitpid調(diào)用只能清理一個子進程,清理多個子進程應(yīng)使用循環(huán)。 wait、waitpid基本上都是在父進程調(diào)用。
1、wait函數(shù)
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status); ?
????????功能: 等待任意一個子進程結(jié)束,如果任意一個子進程結(jié)束了,此函數(shù)會回收該子進程的資源。
????????參數(shù): status : 進程退出時的狀態(tài)信息。
????????返回值: 成功:已經(jīng)結(jié)束子進程的進程號 失敗: -1
????????注意:
- 調(diào)用wait的進程會阻塞(掛起)、直到該函數(shù)返回才被喚醒。
- 若調(diào)用進程沒有子進程,該函數(shù)立即返回 子進程已經(jīng)結(jié)束,該函數(shù)同樣會立即返回,并且會回收那個早已結(jié)束進程的資源。
- 如果參數(shù)status 的值不是NULL,wait()就會把子進程退出時的狀態(tài)取出并存入其中。這是一個整數(shù)值( int),指出了子進程是正常退出還是被非正常結(jié)束的。
????????狀態(tài)值: int中包含了多個字段,直接使用這個值是沒有意義的,WIFEXITED(status) 如果子進程是正常終止的,取出的字段值非零。 WEXITSTATUS(status) 返回子進程的退出狀態(tài),退出狀態(tài)保存在status變 量的8~16位,在用此宏前應(yīng)先用宏WIFEXITED判斷子進程是否正常退出,正常退出才可以使用此宏。
?2、waitpid函數(shù)
? ? ? ? wiatpid常用于等待多個子進程結(jié)束。
#include<sys/type.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options); ?
?功能: 等待子進程終止,如果子進程終止了,此函數(shù)會回收子進程的資源。
參數(shù):
pid : 參數(shù) pid 的值有以下幾種類型:
- pid > 0 等待進程 ID 等于 pid 的子進程。
- pid = 0 等待同一個進程組中的任何子進程,如果子進程已經(jīng)加入了別的進程組, waitpid 不會等待它。
- pid = -1 等待任一子進程,此時 waitpid 和 wait 作用一樣。
- pid < -1 等待指定進程組中的任何子進程,這個進程組的 ID 等于 pid 的絕對值。
status : 進程退出時的狀態(tài)信息。和 wait() 用法一樣。
options : options 提供了一些額外的選項來控制 waitpid()。
- 0:同 wait(),阻塞父進程,等待子進程退出。
- WNOHANG:沒有任何已經(jīng)結(jié)束的子進程,則立即返回。
- WUNTRACED:如果子進程暫停了則此函數(shù)馬上返回,并且不予以理會子進程的結(jié)束狀態(tài)。(由于涉及到一些跟蹤調(diào)試方面的知識,極少用到)
返回值: waitpid() 的返回值比 wait() 稍微復(fù)雜一些,一共有 3 種情況:
- 當(dāng)正常返回的時候,waitpid() 返回收集到的已經(jīng)回收子進程的進程號;
- 如果設(shè)置了選項 WNOHANG,而調(diào)用中 waitpid() 還有子進程在運行,且沒有子進程退出,返回0; 父進程的所有子進程都已經(jīng)退出了 返回-1; 返回>0表示等到一個子進 程退出
- 如果調(diào)用中出錯,則返回-1,這時 errno 會被設(shè)置成相應(yīng)的值以指示錯誤所在, 如:當(dāng) pid 所對應(yīng)的子進程不存在,或此進程存在,但不是調(diào)用進程的子進程,waitpid() 就會出錯返回,這時 errno 被設(shè)置為 ECHILD
waitpid等價于wait的案例:
六、創(chuàng)建多個子進程
1、創(chuàng)建2個子進程出現(xiàn)的問題
2、防止子進程 創(chuàng)建孫進程?
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define N 3
int main(int argc,char *argv[])
{//創(chuàng)建3個子進程int i=0;for(;i<N;i++){pid_t pid=fork();if(pid==0)//防止子進程創(chuàng)建孫進程{break;}}//判斷具體的子進程if(i==0)//子進程1{//完成任務(wù)Aint i=3;for (; i > 0; i--){printf("子進程%d工作剩余時間%d\n",getpid(),i);sleep(1);}_exit(-1);}else if(i==1)//子進程2{//完成任務(wù)Bint i=5;for (; i > 0; i--){printf("子進程%d工作剩余時間%d\n",getpid(),i);sleep(1);}_exit(-1);}else if(i==2)//子進程3{//完成任務(wù)Cint i=7;for (; i > 0; i--){printf("子進程%d工作剩余時間%d\n",getpid(),i);sleep(1);}_exit(-1);}else if(i==N)//父進程{//回收子進程資源while(1){pid_t pid=waitpid(-1,NULL,WNOHANG);//不阻塞if(pid>0){printf("子進程%d退出\n",pid);}else if(pid==0)//還有子進程在運行{continue;}else if(pid==-1){printf("所有子進程已結(jié)束\n");break;}}}return 0;
}
?
七、 進程相關(guān)
1、終端?
????????用戶通過終端登錄系統(tǒng)后得到一個Shell進程,這個終端成為Shell進程的控制終端(Controlling Terminal),進程中,控制終端是保存在PCB中的信息,而 fork會復(fù)制PCB中的信息,因此由Shell進程啟動的其它進程的控制終端也是這個終端。
2、進程組?
????????一個或多個進程的集合,也稱之為作業(yè)。當(dāng)父進程創(chuàng)建子進程的時候,默認子進程與父進程屬于同一進程組。當(dāng)bash創(chuàng)建進程時,該進程自己創(chuàng)建與自己ID相同的進程組,不與父進程同屬于一個進程組。
????????進程組ID為第一個進程ID(組長進程): 進程ID和進程組ID相同的進程就是 組長進程。
????????可以使用kill -SIGKILL -進程組ID(負的)(正的為組長進程)來將整個進程組內(nèi)的進程全部殺死 只要進程組中有一個進程存在,進程組就存在,與組長進程是否終止無關(guān)。 進程組生存期:進程組創(chuàng)建到最后一個進程離開(終止或轉(zhuǎn)移到另一個進程組)。
#include<unistd.h>
pid_t getpgrp(void);?
功能:獲取當(dāng)前進程的進程組ID
參數(shù):無
返回值:總是返回調(diào)用者的進程組ID
pid_t getpgid(pid_t pid);
功能:獲取指定進程的進程組ID
參數(shù): pid:進程號,如果pid = 0,那么該函數(shù)作用和getpgrp一樣
返回值: 成功:進程組ID ????????失敗:-1
int setpgid(pid_t pid, pid_t pgid)
功能: 改變進程默認所屬的進程組。通??捎脕砑尤胍粋€現(xiàn)有的進程組或創(chuàng)建一個新進程組。
參數(shù): 將參1對應(yīng)的進程,加入?yún)?對應(yīng)的進程組中
返回值: 成功:0 失敗:-1
?3、會話
????????會話是一個或多個進程組的集合。 一個會話可以有一個控制終端。 一個會話中的幾個進程組可被分為一個前臺進程組以及一個或多個后臺進程組;如果一個會話有一個控制終端,則它有一個前臺進程組,其它進程組為后臺進程組;如果終端接口檢測到斷開連接,則將掛斷信號發(fā)送至控制進程(會話首進程)。
????????如果進程ID==進程組ID==會話ID 那么該進程為會話首進程。
創(chuàng)建新會話的步驟:
- 調(diào)用進程不能是進程組組長,該進程變成新會話首進程(session header)
- 該調(diào)用進程是組長進程,則出錯返回 。
- 該進程成為一個新進程組的組長進程
- 需有root權(quán)限(ubuntu不需要)
- 新會話丟棄原有的控制終端,該會話沒有控制終端
- 建立新會話時,先調(diào)用fork, 父進程終止,子進程調(diào)用setsid?
#includ<unistd.h>
pid_t getsid(pid_t pid);
功能:獲取進程所屬的會話ID
參數(shù): pid:進程號,pid為0表示查看當(dāng)前進程session ID
返回值: 成功:返回調(diào)用進程的會話ID 失敗:-1
#include<unistd.h>
pid_t setsid(void);
功能: 創(chuàng)建一個會話,并以自己的ID設(shè)置進程組ID,同時也是新會話的ID。調(diào)用了setsid函數(shù)的進程,既是新 的會長,也是新的組長。
參數(shù):無
返回值: 成功:返回調(diào)用進程的會話ID 失敗:-1 ?
?4、創(chuàng)建守護進程
- 創(chuàng)建子進程,父進程退出(必須) 所有工作在子進程中進行形式上脫離了控制終端
- 在子進程中創(chuàng)建新會話(必須) setsid()函數(shù) 使子進程完全獨立出來,脫離控制。
- 改變當(dāng)前目錄為根目錄(不是必須) chdir()函數(shù) 防止占用可卸載的文件系統(tǒng) 也可以換成其它路徑?
- 重設(shè)文件權(quán)限掩碼(不是必須) umask()函數(shù) 防止繼承的文件創(chuàng)建屏蔽字拒絕某些權(quán)限,增 加守護進程靈活性。
- 關(guān)閉文件描述符(不是必須) 繼承的打開文件不會用到,浪費系統(tǒng)資源,無法卸載
- 開始執(zhí)行守護進程核心工作(必須) 守護進程退出處理程序模型?
八、 vfork創(chuàng)建子進程
1、vfork函數(shù)說明?
?????????vfork函數(shù):創(chuàng)建一個新進程
pid_t vfork(void);
功能: vfork函數(shù)和fork函數(shù)一樣都是在已有的進程中創(chuàng)建一個新的進程,但它們創(chuàng)建的子進程是有區(qū)別的。
返回值: 創(chuàng)建子進程成功,則在子進程中返回0,父進程中返回子進程ID。出錯則返回-1。?
2、vfork函數(shù)和fork函數(shù)的區(qū)別?
?????????區(qū)別1:vfork創(chuàng)建的子進程 會保證子進程先運行,只有當(dāng)子進程退出(調(diào)用 exec)的時候,父進程才運行。
?區(qū)別2:vfork創(chuàng)建的子進程 和父進程 共用一個空間。
九、exec函數(shù)族
????????exec函數(shù)族功能:在進程中 啟動另一個進程。?
#include<unistd.h>
- int execl(const char *path, const char *arg, .../* (char *) NULL */);
- int execlp(const char *file,cconst 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[]);
- int execve(const char *filename, char *const argv[], char *const envp[]); ?
?????????函數(shù)中有l(list)表明使用列表方式傳參,函數(shù)中有v(vector)表明使用指針數(shù)組傳參。 函數(shù)中有p(path)表明 到系統(tǒng)環(huán)境中 找可執(zhí)行性文件 函數(shù)中有e(evn) 表明exec可以使用環(huán)境變量值
案例1:在代碼中使用execl執(zhí)行l(wèi)s命令
查看ls命令的路徑:?
?
一個進程調(diào)用exec后不會返回,exec函數(shù)族取代調(diào)用進程的數(shù)據(jù)段、代碼段和堆棧段。除了進程ID,進程還保留了下列特征不變: 父進程號 進 程組號 控制終端 根目錄 當(dāng)前工作目錄 進程信號屏蔽集 未處理信號 ...?