網(wǎng)站建設和域名備案注冊推廣賺錢一個80元
進程控制
(創(chuàng)建、終止,等待,程序替換)
進程創(chuàng)建:
pid_t fork();父子進程,數(shù)據(jù)獨有,代碼共享,各有各的地址
pit_t vfork();父進程阻塞,直到子進程exit退出或者程序替換之后(同時運行會出現(xiàn)?;靵y),因為它的父子進程是共用地址
顯然vfork創(chuàng)建子進程效率更高,但是fork在實現(xiàn)寫時拷貝技術后效率得到大大提升
寫時拷貝技術:子進程創(chuàng)建出來后,有自己的虛擬地址,有自己的頁表,但是并沒有給子進程重新開辟數(shù)據(jù)的空間進行拷貝,而是等到“寫時”–這塊空間中的數(shù)據(jù)即將要發(fā)生變化時,給子進程重新開辟,避免了申請空間但子進程不用,而造成的效率降低
終止:main函數(shù)return退出(僅限于main,因為main是程序的入口函數(shù),運行完畢就會退出)
坤函數(shù):void exit(int retval) ;系統(tǒng)調(diào)用接口 void _exit(int retval);(不刷新緩沖區(qū),因為對于系統(tǒng)來說就沒有緩沖區(qū)這個概念,自然就不存在刷新這一說,坤函數(shù)是有人編寫的,為了提高io效率而設置有緩沖區(qū))
exit(0);return 0;給出的返回值就是進程的返回值
//會創(chuàng)建多少個子進程(main進程不算)
int main(int argc,char* argv[])
{fork();fork()&&fork()||fork();fork();
}
進程等待:父進程創(chuàng)建子進程后,等待子進程退出,獲取退出子進程的退出碼釋放子進程資源,避免僵尸進程。
操作: int wait(int* status) ; status參數(shù)是一個int型空間地址,用于向指定空間存放子進程的退出返回值
wait:阻塞等待任意一個子進程退出,獲取返回值,釋放資源
int waitpid(pid_t pid,int* status,int options);
waitpid:可以等待任意一個子進程退出,或者等待指定的子進程退出,并且等待可以阻塞也可以非阻塞。返回值:子進程pid 0–沒有子進程 ; 出錯返回-1
pid > 0等待指定pid子進程退出 ; -1表示任意
options : 0–默認阻塞等待 ;WNOHANG–設置為非阻塞(當前沒有子進程會立即報錯返回)
進程的退出碼:status
status總共四個字節(jié),實際的退出碼保存在低16位的高8位部分,進程異常退出信號值保存在低7位
程序替換:替換一個進程正在調(diào)度管理的程序(讓一個已有pcb調(diào)度管理一個新的程序運行)
實現(xiàn):通過exec函數(shù)族(execl,execlp,execle,execv,execvp,execve),將新程序加載到內(nèi)存中,修改當前pcb的頁表映射信息,初始化虛擬地址空間,這時候pcb將調(diào)度新的程序運行
阻塞操作簡單,但是對資源利用率較低
非阻塞操作復雜一些(通常要循環(huán)操作),資源利用率高
在合適的時候采用
#include<stdio.h> 2 #include<unistd.h>3 #include<sys/types.h>4 #include<sys/wait.h>5 #include<stdlib.h>6 int main()7 {8 pid_t ret=fork();9 if(ret<0)10 perror("fork error");11 else if(ret==0)12 {13 printf("i am child process;pid:%d ppid:%d\n",getpid(),getppid());14 printf("3秒后退出");15 sleep(3);16 exit(100);//設置退出碼為10017 }18 printf("父進程;pid:%d\n",getpid());19 int status=0;20 pid_t st=wait(&status);21 if((status&0x7f)==0)//異常退出值,存在第七位,為0表示正常退出,!0為異常退出22 printf("等待成功,子進程pid:%d,狀態(tài)信息:status=%d,退出碼是:%d\n",st,status,(status>>8&0xff));23 else24 printf("子進程異常退出\n");25 return 0;26 }
程序替換:加載一個新的程序到內(nèi)存中,將指定的進程的pcb頁表映射信息進行修改,讓其調(diào)度管理新的程序運行。
操作接口:
** int execve(char* path,char* argv[],char* env[]) **
功能:將path這個路徑名所指定的程序加載到內(nèi)存中,然后讓當前進程調(diào)度管理這個程序的運行額,而程序運行有可能會有運行參數(shù)(argv)和環(huán)境變量(env)
返回值:失敗返回-1 ; 替換成功沒有返回值(因為替換成功就運行新的程序了)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{int a=0;a++;//execl("/usr/bin/ls","ls","-la",NULL);//可變參數(shù)列表,要以null結(jié)尾//execlp("ls","ls","-lh",NULL);//不需要給path路徑,但要在PATH中能找到extern char** environ;//execle("/usr/bin/pwd","/usr/bin/pwd",NULL,NULL);//可變參數(shù)列表以NULL結(jié)尾,組織變量設為NULLchar* argv[10]={NULL};argv[0]="/usr/bin/tree";//argv[1]="NULL";execve("/usr/bin/tree",argv,environ);//系統(tǒng)接口,其他都是C語言對系統(tǒng)調(diào)用接口的封裝printf("%s",strerror(errno));printf("%d\n",a++);return 0;
}
shell是一個軟件,命令行解釋器,捕捉用戶的輸入,了解用戶想要什么,執(zhí)行對應的shell指令程序,起到用戶和內(nèi)核之間的溝通橋梁
用程序替換實現(xiàn)簡單shell(minshell),這個代碼還有許多可升級的地方,比如它無法刪除,如果輸入錯誤,那么只能讓它出錯,一次下次重輸,沒有保存之前輸入的指令,僅僅只是簡單通過字符串接收指令,通過程序替換執(zhí)行
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<string.h>
/** 模擬實現(xiàn)shell,運用程序替換* */
int main()
{ while(1){printf("【user%host ~ 】$ ");fflush(stdout);char cmd[1024]={0};fgets(cmd,1023,stdin);cmd[strlen(cmd)-1]='\0';int argc=0;char*argv[32]={NULL};char* ptr=cmd;argv[argc++]=strtok(cmd," ");//字符串分割while((argv[argc]=strtok(NULL," "))!=NULL){argc++;}if(strcmp(argv[0],"cd")==0){chdir(argv[1]);continue;}pid_t child_pid=fork();if(child_pid<0){perror("fork error");continue;}else if(child_pid==0){execvp(argv[0],argv);perror("execvp error");exit(-1);}wait(NULL);}return 0;
}