進程創建

進程創建是作業系統執行程式的需要或者用戶或進程要求創建一個新的進程。進程創建首先是在進程表中為進程建立一個進程控制塊PCB,採用fork()系統調用將複製執行進程的PCB塊,U區和記憶體圖像到新的進程。 主要內容包括:進程創建原語、fork()系統調用的編程舉例和UNIX V6的fork()源碼分析。

基本介紹

  • 中文名::進程創建
  • 外文名::process creat
  • 別名::進程創建原語,創建進程,fork()
  • 使用類型::作業系統
  • 開發者::UNIX
  • 發行商::AT&T
  • 支持語言::UNIX/Linux的C語言
  • 源碼類型::作業系統代碼
  • 開發語言::C語言
  • 原版名稱::UNIX V6
  • 開發時間::1970年代
  • 檔案類型::C語言源程式
進程創建時機,進程創建原語,fork函式的程式設計方法,1.fork()系統調用格式,2.fork程式設計,UNIXV6fork()原始碼剖析,1.數據結構proc和user,2.fork()源程式分析,

進程創建時機

進程創建,是指作業系統創建一個新的進程。UNIX系統用fork()系統調用,而windows系統用CreatProcess()。進程創建的時機有:
(1)系統初始化。系統的調度進程創建init進程。
(2)執行中的進程調用了fork()系統函式。程式中有fork()函式。
(3)用戶登錄,用戶命令請求創建進程。例如:用戶雙擊一個圖示。
(4)一個批處理作業初始化。大型機、高性能計算機用戶提交一個課題,則系統建立作業控制塊,在作業調度後在系統記憶體中創建進程。

進程創建原語

進程藉助創建原語實現創建一個新進程。首先為被創建進程在進程表集中區建立一個PCB--UNIX系統還要為進程創建U區和記憶體映像,從進程表索取一個空白PCB表目,記錄它的下標;然後,把調用者提供的所有參數(見PCB塊的內容),作業系統分配給新進程的PID和調用者的PID,就緒狀態和CPU記賬數據填入該PCB塊;最後,把此PCB塊分別列置到就緒佇列RQ和進程隸屬關係族群中。
UNIX系統使用fork()函式創建新進程時,為子進程複製EP進程的記憶體映像並不是主要目標。這時,若用exec()執行一個新程式,則子進程的正文段將全部更換,而數據段也將更新。
創建原語可描述如下:
Procedurecreate(n,S0,K0,M0,R0,acc)
begin
i:=getinternalname(n);//進程表下標
i.id:=n;i.priority:=K0;//進程PID,進程優先權
i.CPUstate=S0;i.mainstore:=M0;//初始CPU狀態,記憶體地址
i.resources:=R0;i.status:=readys;//資源清單,就緒狀態
j:=EP;i.parent:=j;i.progeny:=φ;//父進程是EP進程,子進程空
j.progeny:=i;//進程隸屬關係
i.sdata=RQ;insert(RQ,i);//到就緒進程佇列排隊
continue
end

fork函式的程式設計方法

1.fork()系統調用格式

系統調用1:fork
#include<types.h>
#include
pid_tfork()
返回值:子進程返回0,父進程返回子進程ID,出錯返回-1。
功能:創建一個進程。
fork的三個返回值
fork的三個返回值fork的三個返回值

2.fork程式設計

源程式
#include
#include
#include<types.h>
int main(intargc,char*argv[])
{
intvalue=5;
pid_tpid;
pid=fork();//fork一個子進程
if(pid<0){//返回值小於0
printf(“forkfailed\n”);
exit(-1);
}
elseif(pid==0){//子進程
value+=15;
printf(“\nchildprocesspid=%d”,getpid());
printf(“\nvalue=%d”,value);
exit(0);
}
elseif(pid>0){//EP進程(parentprocess)
value+=5;
pirntf(“\nvalue=%d”,value);
printf(“\EPprocesspid=%d”,getpid());
printf(“\nvalue=%d”,value);
exit(0);
}
}
在程式設計中,fork()的套用最重要的是:掌握利用對子進程和EP進程的兩個不同返回值的方法。經典方式是使用 if語句,if((pid=fork())==0)是子進程完成任務的編程範圍,應編寫與子進程功能相關的語句;而elseif(pid>0)則是EP進程(parentprocess)完成任務的語句範圍。在以上程式中,兩個進程完成的功能相同,然而在大多數情況,它們的功能不同,這也是使用fork()的原因之一。應注意一個函式同時有不同返回值的問題,這是和以前的編程經驗不同的地方。
為了避免作業系統崩潰,pid<0是必須考慮的情況,創建進程失敗稱為異常。在UNIX系統程式中,不能有考慮不到的異常情況,這是編程能力的高低區別。
新創建的子進程和EP進程有各相互獨立的數據段,EP進程和子進程對同一個變數所做的任何改變都是獨立的,不會放映到另一個進程的存儲器中。因此,value在子進程中的值為20,而在EP進程中的值則為10。變數value在不同的進程中有不同的值,充分說明儘管子進程是複製EP進程而來,有相同的正文段,然而,它們的數據段各自獨立。EP進程不能訪問子進程的數據段,所以它的第一個printf()語句輸出的value值為5。

UNIXV6fork()原始碼剖析

1.數據結構proc和user

UNIXV6採用進程控制塊PCB和U區管理和表示一個進程控制信息。PCB塊使用結構proc表示,稱為進程基本控制塊,而U區使用結構user表示稱為進程擴充控制塊。進程控制信息分為兩部分的原因是:結構proc常駐記憶體,管理經常被作業系統核心訪問的那部分信息;而結構user管理進程分配的資源,包括打開的檔案或目錄等信息,有可能被移至外存交換空間。由於作業系統核心只需要當前執行進程的user,因此當某一進程被換出至外存時,對應的U區被移至交換空間。這是早年計算機記憶體容量緊張造成的。
PCB塊原本是進程控制塊的統稱,但是常用來表示proc,所以今後PCB塊都表示進程基本控制塊。
一.PCB塊
#include
#define NPROC50
structproc
{
charp_stat;//狀態。CPU相關
SRUN:可執行。執行和就緒
SIDL:進程生成中。fork()
SSLEEP:高阻塞
SWAIT:低阻塞
SSTOP:trace
SZOME:終止還沒回收
charp_flag;//標誌。記憶體相關(是否調到外存)
SSYS:系統進程。procpid=0
init進程是proc,並不是系統進程
SLOAD:在記憶體中(可執行)
SLOCK:進程上鎖不被調出
SSWAP:進程在外存
r5,r6
STRC:跟蹤狀態
SWTED:在被跟蹤時使用
charp_pri;//進程優先權。可變。
charp_sig;//進程接收到的信號,軟中斷信號。
//記錄其它進程發來的信號
charp_uid;//進程所屬用戶UID。哪一個用戶登錄。
charp_time;//進程的存在時間。
//給出進程的執行時間和對資源的利用情況。
當剛交換到記憶體或外存交換區時,p_time=0。
charp_cpu;//CPU累計時間,在CPU上運行的時間。
charp_nice;//用戶調整優先權的值
//偏置值nice,固定值。用戶的許可權。
intp_ttyp://發出進程的終端號,uid所在終端。與信號相關。
intp_pid;//進程PID
intP_ppid;//父進程PID,創建進程的PID。
//當父進程退出,則子進程的父進程可為init進程。
intp_addr;//數據段的物理地址。進程PPDA和U區的地址
intp_size;//數據段長度。可交換映像大小
intp_wchan;//阻塞原因。
//事件描述符,記錄使進程進入阻塞狀態的原因。
可為系統資源,例如:記憶體緩衝區。
int*p_textp;//代碼段。源程式編譯的執行檔在text[]中的地址。
}proc[NPROC];
proc[NPROC]數組是進程表,NPROC規定了UNIX作業系統允許擁有的最多進程數。結構proc包含15個成員。PCB塊的proc.p_stat和proc.p_flag常組合使用。根據PCB塊的描述,它們分為七類:
1.進程標識符proc.p_pid它等於全局變數mpid。mpid的變化範圍是0~(215-1)。儘管很長時間不會重複,然而當mpid是最大值是,它將又一次從0開始計數。應注意mpid與NPROC不同。
2.進程狀態proc.p_stat和進程標誌proc.p_flag
與進程能否被調度在CPU上運行密切相關,因此進程狀態又稱為進程調度狀態。進程的各種調度狀態可依據一定的原因和條件變化。一個已存在系統中的進程不斷在這些狀態中變化。
UNIXV6使用進程調入調出系統,並不是現在的虛擬記憶體管理系統。進程調入調出是完整的記憶體映像調出,包括PPDA。進程調出的標誌並不是代碼段調出到外存,而是PPDA調出到外存。Perprocessdataarea(PPDA)由進程的U區和核心棧區域構成,在數據段的首部,有1kB長度。
當EP進程生成子進程時,狀態proc.p_stat=SIDL,而且當時它不可能被調出記憶體,所以標誌proc.p_flag=SLOCK。因此,=。就緒進程很少被調出記憶體,因此大多數情況=。
3.CPU運行信息和進程優先數進程優先數動態變化,相關參數有三項。第一項proc.p_pri,值越小優先權越高。它是處理機調度的主要依據。數值變化範圍-100~127,進程調度的優先權不能有很豐富的變動。第二項proc.p_cpu反映了進程使用處理機的程度。proc.p_cpu值越大表示進程使用CPU的時間越長,因此被調度的可能性就越小。它是UNIX作業系統計算p_pri的一個主要參考數據。第三項是proc.p_nice計算進程優先數時所用的一個偏置值。在三項中,是用戶唯一能設定的一個值。
UNIX作業系統的優先權調度算法見第1.4節。
4.進程的記憶體映像地址表示進程圖像最近一次調入調出後,在記憶體或外存交換區的時間。這是0#進程在內、外存之間傳送繼承的一個主要依據。proc.p_addr不僅是數據段,而且是棧區域和PPDA的物理地址。它們同在數據段中,根據APR頁表和它們的區域長度,能計算出實際的物理地址。因此,不能說PCB塊中沒有給出棧區域的物理地址。proc.p_size=數據區域長度+棧區域長度+PPDA長度。根據proc.p_addr,proc.p_textp,proc.p_size能找到進程的記憶體圖像,若進程被調出到外存則proc.p_addr是進程數據段在外存的地址。
7.進程的組織隸屬關係用戶標識符proc.p_uid保存在一份用戶花名冊檔案中/etc/passwd,每一個合法用戶在該檔案中都有一個記錄,格式為:
loginname:password:uid:gid::loginworkingdir:shell
loginname是用戶進入系統時使用的登錄名;password是密碼形式的用戶口令;uid、gid是高級用戶或者系統管理員分配給該用戶的標識符和所在組號(0~255);最後兩項分別是用戶工作目錄和作業系統提供給用戶的命令程式。系統管理員的proc.p_uid=0。
proc.p_ppid是進程的父進程標識符,在進程樹中,除了0#進程以外,其它進程都是父進程要求生成的,因此都不是系統進程。
二、U區
#include
structuser
{
intu_rsav;//進程切換時保存暫存器r5,r6的值(數據段)
intu_fsav;//處理器為PDP-11/40時不用
charu_segflg;//讀寫檔案時使用的標誌變數
charu_error;//出錯時用來保存錯誤代碼
charu_uid;//實效用戶標識符
charu_gid;//實效組
charu_ruid;//實效用戶
charu_rgid;//實際組
int*u_procp;//U區對應的PCB塊
char*u_base;//讀寫檔案時用於傳遞參數,起始地址
char*u_count;//讀寫檔案時傳遞參數,長度
char*u_offset;//讀寫檔案時傳遞參數,活動偏移量
int*u_cdir;//當前目錄對應的數組inode[]的元素
charu_dbuf[DIRSIZ];//namei()
char*u_dirp;
struct{
intu_ino;
charu_name[DIRSIZ];
}u_dent;
int*u_pdir;
intu_uisa;
intu_uisd;
intu_ofile[NOFILE];//進程打開的檔案。外部設備是設備檔案/dev
intu_arg;
intu_tsize;//代碼段長度
intu_dsize;//數據區域長度
intu_ssize;//棧區域長度
intu_sep;
intu_qsav;//處理信號時保存r5,r6當前值
intu_ssav;//進程調出時保存r5,r6當前值
intu_signal[NSIG];
intu_utime;
intu_stime;
intu_cutime;
intu_cstime;
intu_ar0;//系統調用,操作通用暫存器或PSW時使用
intu_prof;
charu_intflg;
}u;
.globl–u
-u=140000
作業系統通過全局變數u訪問執行進程的數據段。全局變數u的地址0140000是八進制數,高3位是110,為6。所以APR頁表的第6頁面被選擇,而低位全部是0,所以u指向作業系統核心空間第6頁的起始地址。所以作業系統通過核心空間第6頁的起始地址找到執行進程數據段的位置,用proc.p_addr標識。

2.fork()源程式分析

#include
#includeken.h>
fork()
{
registerstructproc*p1,*p2;
p1=u.u_procp;//執行進程u是全局變數
for(p2=&proc;p2<&proc[NPROC];p2++)//proc[]={NULL,proc[i]}
if(p2->p_stat==NULL)
gotofound
u.u_error=EAGAID;//進程數量超過系統規定
gotoout;
found://若進程表有空白PCB塊
if(newproc()){//newproc()向EP進程返回0,向新進程返回1
u.u_ar0[R0]=p1->p_pid;//EP進程進程號
u.u_cstime=0;u.u_cstime=0;//設定CPU時間
u.u_stime=0;
u.u_cutime=0;u.u_cutime=0;
u.u_utime=0;
return;
}
u.u_ar0[R0]=p2->p_pid;
//fork()對EP進程的返回值是新進程的PID,存放在u.u_ar0[R0]
out:
u.u_ar0[R7]=+2;//指向EP進程的下一條指令地址
}
newproc()//創建新進程的函式
{
inta1,a2;
structproc*p;*up;
registerstructproc*rpp;
register*rip,n;
p=NULL;
retry:
mpid++;//mpid的值mpid={0}
if(mpid<0){//若mpid分配結束,則從0開始分配
mpid=0;
gotoretry;
}
for(rpp=&proc;rpp<&proc[NPROC];rpp++)
if(rpp->p_stat==NULL&p=NULL)//p_stat={NULL,pid}
p=rpp;//若有空白PCB塊,記錄在p中
if(rpp->p_pid==mpid)//若mpid已經分配
gotoretry;//重新分配mpid
}//總結進程表的三種情況proc[]={full,,null*}
If((rpp=p)==NULL)
panic(“noprocs”);
rip=u.u_procp;//賦值新進程的proc。Rip執行進程
up=rip;//保存EP進程的PCB塊
rpp->p_stat=SRUN;//新進程的狀態SRUN就緒
rpp->p_flag=SLOAD;//新進程在記憶體中SLOAD
rpp->p_uid=rip->p_uid;//複製EP進程PCB塊中的值
rpp->p_ttyp=rip->p_ttyp;
rpp->p_nice=rip->p_nice;
rpp->p_textp=rip->p_textp;//新的進程複製EP進程正文段
rpp->p_pid=mpid;//新進程PID=mpid
rpp->p_ppid=rip->p_pid;//新進程的父進程是EP進程
rpp->p_time=0;//CPU執行時間為0
for(rip=&u.u_ofile;rip<&ofile[NOFILE];rip++)
//新進程複製EP進程分配的系統資源,是特殊檔案。
if((rpp=*rip++)!=NULL)
rpp->f_count++;
if((rpp=up->p_textp)!=NULL){//複製共享代碼段
rpp->x_count++;//text[]計數器增加1
rpp->x_ccount++;
}
u.u_cdir->i_count++;//目錄inode節點計算器增加1
savu(u.u_rsav);//執行進程切換時,保存EP進程的r5,r6到U區
rpp=p;
u.u_procp=rpp;//執行繼承u是新的進程newproc
rip=up;
n=rip->p_size;//複製數據段長度
a1=rip->p_addr;//”原”EP進程數據段地址
rpp->p_size=n;
a2=malloc(coremap,n);//為新進程申請記憶體區域
if(a2==NULL){//若申請的記憶體區域為空,a2={null,address}
rip->p_stat=SIDL;//EP進程狀態為SIDL:創建進程中
rpp->p.addr=a1;//新進程數據段地址=EP進程數據段地址
savu(u.u_ssav);//新的進程調出到外存時保存r5,r6到U區
xswap(rpp,0,0);//複製新進程的數據段到外存交換空間
rpp->p_flag=|SSWAP;//新進程標誌:在外存
rip->p_stat=SRUN;//EP進程狀態還原為SRUN 
}else{//申請的記憶體區域不為空,在記憶體複製數據段
rpp->p_addr=a2;//新進程的數據段地址是申請到的記憶體地址
while(n--)copyseg(a1++,a2--);//複製EP進程的數據段
}
u.u_procp=rip;//執行進程u是EP進程
return(0);//向fork()返回0
}
注意:newproc通過swtch()切換執行,swtch()返回值為1,newproc獲得返回值1。

相關詞條

熱門詞條

聯絡我們