一、背景
之前在《計算機操作系統》這本書中已經多次接觸了進程這一概念,而進程在操作系統中具體是做什麼的呢?卻沒有實際的與進程發生過互動,因此也就沒有實際的感受。對於我來說進程僅僅停留在概念的層面上:進程是程序運行時的內存空間和設置或者說進程就是程序的進行時。沒有過實踐可不好辦,於是就打算進一步的理解進程,為進一步理解進程,就需要對進程進行控制。當然,這個報告中是一些較為簡單的進行控制。
二、進程的理解
概念層面的進程這裡就不說了。我講講實際一些的,自己理解的進程。
在命令行中輸入ps,這裡可以看到兩個簡單的進程的信息。給個參數-l就可以看到詳細的進程信息。
S:status,表示這個進程的狀態,S是說sleep,R是說running。
UID:進程的用戶ID。
PID:進程的進程ID,這個很好理解,進程也需要唯一的數字來標識,和UID、GID引入方式類似。
PPID:父進程的ID,也就是調用這個進程的進程的ID號。從這裡我就可以看到一個進程的父進程是誰。
PRI:prior,進程的優先級。
NI:進程的niceness級別,niceness級別越高這個進程就越往後排。
SZ:size,進程佔用的內存大小。
WCHAN:進程睡眠的原因。剛才也說了,S列中的S是表示sleep睡眠的。這一列就說明了此進程睡眠的原因。
TIME:運行時間。
對以上這些名詞也解釋清楚了,可是一臺計算機怎麼也不至於就這麼兩個進程在運行吧。肯定是有很多很多的系統進程同時作用的結果。接著用-x參數就可以看到如下的系統進程。
系統進程實在太多。我只截取了前面一部分。系統進程大都沒有與終端相連,他們在計算機啟動的時候啟動,而不需要在命令行中啟動他們。
三、子進程的創建
子進程創建使用系統調用fork(),如此正在運行的進程會一分為二,原進程繼續向下執行,而新創建的子進程也會從創建開始的位置繼續向下執行。
而在背後內核做了許多事情,包括分配新的內存塊和內核數據結構,複製原來的進程到新的進程,向運行進程集添加新的進程,將控制返回給兩個進程。這樣兩個進程就兩不相干的繼續朝下運行(並非完全不相干,比如還有父子關係)。
四、父進程等待子進程運行完畢
此時使用系統調用wait(),這個時候父進程就會等待子進程直到子進程運行完畢了才會繼續運行。這個說起來不直觀。我寫了一段等待程序,以此來理解之前的一些概念。
#include
int main()
{
int newpid,newnewpid;
printf("I am a parent,my pid is:%d\n",getpid());
newpid=fork();
if(newpid==0)
{
printf("i am a son,my pid is:%d,and i wanna sleep 5s\n",getpid());
sleep(5);
newnewpid=fork();
if(newnewpid==0)
{
printf("i am a grandson,my pid is %d,and i wanna sleep 10s\n",getpid());
sleep(10);
}
else{
wait(NULL);
printf("I am a son,i wanna sleep 2s\n");
sleep(2);
}
}
else {
wait(NULL);
printf("I am a parent,i wanna sleep 4s\n");
sleep(4);
}
}
運行結果是這個樣子的。實際上正如上面寫的,子進程與孫子進程都睡眠了對應的時間。
另外,通過此程序也可以方便的理解之前說到的父子進程在進程ID方面的關係。
看到PID與PPID的數字,那麼各個進程間的關係也就一目瞭然了。
五、程序調用
想在一個程序中調用另外一段程序使用庫函數execvp。
六、命令解釋器的實現
先來看看運行結果。
此時一直運行著a.out這一程序,而ls是a.out調用的子程序。
以下是實現的程序代碼:
#include
#include
#include
#include
#define ARGLEN 100
#define ARGNUM 20
void execute(char *list[]);
char *makestring(char buf[]);
int main()
{
int argnum;
char argbuf[ARGLEN];
char *arglist[ARGNUM];
while(argnum printf("arg[%d]:",argnum); if(fgets(argbuf,ARGLEN,stdin) && *argbuf!='\n') arglist[argnum++]=makestring(argbuf); else if(argnum>0) { arglist[argnum]=NULL; execute(arglist); argnum=0; } } } void execute(char *list[]) { int re_pid; re_pid=fork(); if(re_pid==-1) { perror("fork error :"); exit(1); } else if(re_pid==0) { execvp(list[0],list); exit(1); } else { wait(NULL); } } char *makestring(char buf[]) { char *cp; void *malloc(size_t ); buf[strlen(buf)-1]='\0'; cp=malloc(strlen(buf)+1); if(cp==NULL) { perror("no memory\n"); exit(1); } strcpy(cp,buf); return cp; } 進程雖然是計算機中最重要的概念之一,但最為概念方面的進程是非常抽象與難以理解的,而自己進行簡單的進程控制之後就發現進程其實並不很難理解。通過實踐,學習到的概念也才會理解的更快更準。七、總結
閱讀更多 有理想的代碼dog 的文章