進(jìn)程是操作系統(tǒng)資源管理的最小單位。是一個動態(tài)的實體,是程序的一次執(zhí)行過程。 進(jìn)程是動態(tài)的,程序是靜態(tài)的; 為了在同一時間內(nèi)能執(zhí)行更多的任務(wù),進(jìn)程內(nèi)部又可劃分了許多的線程。 線程在進(jìn)程內(nèi)部,是比進(jìn)程更小的能獨立運行的基本單位。線程基本上不擁有系統(tǒng)資源,它與同屬于一個進(jìn)程的其他線程共享進(jìn)程擁有的全部資源。 linux下可通過命令ps或pstree查看當(dāng)前系統(tǒng)的進(jìn)程。 進(jìn)程的標(biāo)識 每個進(jìn)程都是通過唯一 的進(jìn)程ID標(biāo)識的。非負(fù)數(shù),每個進(jìn)程除了進(jìn)程ID外還有其它的標(biāo)識符信息,都可以通過相應(yīng)的函數(shù)獲得。這些函數(shù)的聲明在 unistd.h 頭文件中。 獲取進(jìn)程各種標(biāo)識符的函數(shù) pid_t getpid(id) //獲得進(jìn)程ID pid_t getppid(id) //獲得進(jìn)程父進(jìn)程ID pid_t getuid() //獲得進(jìn)程的實際用戶ID pid_t geteuid() //獲得進(jìn)程的有效用戶ID pid_t getgid() //獲得進(jìn)程的實際組ID pid_t getegid(id) //獲得進(jìn)程的有效組ID 實際用戶ID(uid):標(biāo)識運行該進(jìn)程的用戶。 有效用戶ID(euid):標(biāo)識以什么用戶身份來運行進(jìn)程。如:普通用戶A,運行了個程序,是以root身份來運行的,這個程序運行時就具有root權(quán)限。此時實際用戶ID是A用戶的ID,而有效用戶ID是root用戶ID。 實際組ID(gid):實際用戶所屬的組的組ID。 有效組ID(egid):有效組ID是有效用戶所屬的組的組ID。 linux進(jìn)程狀態(tài) 運行狀態(tài)R(runnbale) 可中斷等待狀態(tài)S(sleeping) 不可中斷等待狀態(tài)D(uninterruptible sleep) 僵死狀態(tài)Z(zombile) 停止?fàn)顟B(tài)T(traced or stopped) <(高優(yōu)先級進(jìn)程),N(低優(yōu)先級進(jìn)程),L(內(nèi)存鎖頁面,即頁面不可以被換出內(nèi)存),s(該進(jìn)程為會話首進(jìn)程),l(多線程進(jìn)程),+(進(jìn)程位于前臺進(jìn)程組)。 進(jìn)程控制 主要的系統(tǒng)調(diào)用有 fork:用于創(chuàng)建一個新進(jìn)程 exit:用于終止一個應(yīng)用程序。 exec:用于執(zhí)行一個應(yīng)用程序。 wait:將父進(jìn)程掛起,等待子進(jìn)程終止。 getpid:獲取當(dāng)前進(jìn)程的進(jìn)程ID。 nice:改變進(jìn)程的優(yōu)先級。 進(jìn)程的創(chuàng)建兩種方式 一、由操作系統(tǒng)創(chuàng)建。平等的 二、由父進(jìn)程創(chuàng)建。繼承的 系統(tǒng)調(diào)用fork是創(chuàng)建一個新進(jìn)程的唯一方法,除了極少數(shù)以特殊方式創(chuàng)建的進(jìn)程。如:init 創(chuàng)建一個子進(jìn)程之后,父進(jìn)程和子進(jìn)程爭奪CPU,搶到的執(zhí)行,另一個掛起等待。 如果想要父進(jìn)程等待子進(jìn)程執(zhí)行完畢以后在繼續(xù)執(zhí)行,可以在fork操作之后調(diào)用wait或waitpid。 #inlcude<sys/types.h> #inlcude<unistd.h> pid_t fork(void); fork函數(shù)調(diào)用一次返回兩次,父進(jìn)程返回值為新創(chuàng)建的子進(jìn)程的進(jìn)程ID 子進(jìn)程I返回值為0, fork.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> int main(void) { pid_t pid; printf("Process Creation Study\n"); pid=fork(); switch(pid) { case 0: printf("Child process is running ,Current Pid is %d,ParentPid is %d\n",pid,getppid()); break; case -1: perror("Process creation failed\n"); break; default: printf("Patent process is running , ChildPid is %d,Parentpid is %d\n",pid,getpid()); break; } exit(0); } fork2.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> int main(void) { pid_t pid; char *msg; int k; printf("Process Creation Study\n"); pid=fork(); switch(pid) { case 0: msg="Child process is running "; k=3; break; case -1: preeor("Process creation failed\n"); break; default: msg="Parent process is running "; k=5; break; } while(k>0) { puts(msg); sleep(1); k--; } exit(0); } 孤兒進(jìn)程 如果一個子進(jìn)程的父進(jìn)程先于子進(jìn)程結(jié)束,子進(jìn)程就成為一個孤兒進(jìn)程,它有init進(jìn)程收養(yǎng),成為init進(jìn)程的子進(jìn)程。 fork3.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> int main(void) { pid_t pid; pid=fork(); switch(pid) { case 0: while(1) { printf("A background process,PID:%d\n,Parent ID:%d\n",getpid(),getppid()); sleep(3); } case -1: perror("Process creation failed\n"); exit(-1); default: printf("I am parent process ,my pid is %d\n",getpid()); exit(0); } return 0; } vfork函數(shù) 也可以創(chuàng)建一個新進(jìn)程,于fork的異同 1、都是調(diào)用一次返回兩次。 2、使用fork創(chuàng)建一個子進(jìn)程時,子進(jìn)程只是完全復(fù)制父進(jìn)程的資源。這樣得到的子進(jìn)程獨立于父進(jìn)程,有良好的并發(fā)性。而使用vfork創(chuàng)建的子進(jìn)程時,操作系統(tǒng)并不將父進(jìn)程的地址空間完全復(fù)制到子進(jìn)程,用vfork創(chuàng)建的子進(jìn)程共享父進(jìn)程的地址空間,子進(jìn)程的運行完全在父進(jìn)程地址空間上。 子進(jìn)程對該地址空間中任何數(shù)據(jù)的修改同樣為父進(jìn)程所見。 3、使用fork創(chuàng)建一個子進(jìn)程是,是那個進(jìn)程先運行取決于系統(tǒng)的調(diào)度算法。而vfork一個進(jìn)程時,vfork保證子進(jìn)程先運行,當(dāng)它調(diào)用exec或exit之后,父進(jìn)程才可能被調(diào)度運行。如果在調(diào)用exec或exit之前子進(jìn)程要依賴父進(jìn)程的某個行為,就會導(dǎo)致死鎖。 創(chuàng)建守護(hù)進(jìn)程 守護(hù)進(jìn)程(daemon)指在后臺運行的沒有控制終端與之相連的進(jìn)程。獨立于控制終端,通常周期性的執(zhí)行某種任務(wù)。linux中的大多數(shù)服務(wù)器就是用守護(hù)進(jìn)程的方式實現(xiàn)的。在后臺運行。 啟動方式: linux系統(tǒng)啟動時從啟動腳本/etc/rc.d中啟動 有作業(yè)規(guī)劃進(jìn)程crond啟動 由用戶終端執(zhí)行 daemon.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<signal.h> #include<sys/param.h> #include<sys/stat.h> #include<time.h> #include<syslog.h> int init_datmon(void) { int pid; int i; .................. ....... } 進(jìn)程退出 (1)正常退出 在main函數(shù)中執(zhí)行return。 調(diào)用exit函數(shù)。 調(diào)用_exit函數(shù)。 (2)異常退出 調(diào)用about函數(shù)。 進(jìn)程收到某個信號,而該信號是程序終止。 不管那種退出方式,最終都會執(zhí)行內(nèi)核中的同一段代碼。這段代碼用來關(guān)閉進(jìn)程所有已打開的文件描述符,釋放它所有占用的內(nèi)存和其他資源。 各種退出方式的比較: a、exit和return的區(qū)別:exit是一個函數(shù),有參數(shù);而return是函數(shù)執(zhí)行完后的返回。exit把控制權(quán)交給系統(tǒng),而return將控制權(quán)交給調(diào)用函數(shù)。 b、exit和about的區(qū)別:exit是正常終止進(jìn)程,而about是異常終止。 c、exit(int exit_code):exit中的參數(shù)exit_code為0代表進(jìn)程正常終止,若為其他值表示程序執(zhí)行過程中有錯誤發(fā)生 d、exit()和_exit()的區(qū)別:exit在頭文件stdlib.h中聲明,而_exit()聲明在頭文件unistd.h中 兩個函數(shù)都能正常終止進(jìn)程,但是_exit()會執(zhí)行后立即返回給內(nèi)核,而exit()要先執(zhí)行一些清除操作,然后將控制權(quán)交給內(nèi)核。 |
|