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