多程式程式設計 (轉)

worldblog發表於2007-12-10
多程式程式設計 (轉)[@more@]
多程式


寫在前面的話
 本文主要根據本人在上的程式設計實踐總結而成, 既做為自己在
一個時期內程式設計實踐的部分總結, 又可成為文章發表. 對UNIX員初學者來
說是一個小小的經驗, 僅供參考; 對UNIX老手來說則不值一哂, 請各位多多指
教.

一.多程式程式的特點
 由於UNIX系統是分時多系統, 按時間片分配給各個使用者使用, 而在
實質上應該說CPU按時間片分配給各個程式使用, 每個程式都有自己的執行環境
以使得在CPU做程式切換時不會"忘記"該程式已計算了一半的"半成品". 以D
的概念來說, 程式的切換都是一次"DOS中斷"處理過程, 包括三個層次:
 (1)使用者資料的儲存: 包括正文段(TEXT), 資料段(DATA,BSS), 棧段
 (STACK), 共享段(SHARED MEMORY)的儲存.
 (2)暫存器資料的儲存: 包括PC(program counter,指向下一條要的指
 令的地址), PSW(processor status ,處理機狀態字), SP(stack
 pointer,棧指標), PCBP(pointer of process control block,程式控
 制塊指標), FP(frame pointer,指向棧中一個的local變數的首地
 址), AP(augument pointer,指向棧中函式的實參位置), ISP(
 interrupt stack pointer,中斷棧指標), 以及其他的通用暫存器等.
 (3)系統層次的儲存: 包括proc,u,虛擬空間管理表格,中斷處理棧.
以便於該程式再一次得到CPU時間片時能正常執行下去.
 既然系統已經處理好所有這些中斷處理的過程, 我們做程式還有什麼要擔
心的呢? 我們儘可以使用系統提供的多程式的特點, 讓幾個程式精誠合作, 簡
單而又高效地把結果給它搞出來.
 另外,UNIX系統本身也是用C語言寫的多程式程式,多程式程式設計是UNIX的特
點,當我們熟悉了多程式程式設計後,將會對UNIX系統機制有一個較深的認識.
 首先我介紹一下多程式程式的一些突出的特點:
 1.並行化
 一件複雜的事件是可以分解成若干個簡單事件來解決的, 這在程式設計師
 的大腦中早就形成了這種概念, 首先將問題分解成一個個小問題, 將小問
 題再細分, 最後在一個合適的規模上做成一個函式. 在工程中也是這
 麼說的. 如果我們以圖的方式來思考, 一些小問題的計算是可以互不干擾
 的, 可以同時處理, 而在關鍵點則需要統一在一個地方來處理, 這樣程式
 的執行就是並行的, 至少從人的時間觀念上來說是這樣的. 而每個小問題
 的計算又是較簡單的.
 2.簡單有序
 這樣的程式對程式設計師來說不亞於管理一班人, 程式設計師為每個程式設計
 好相應的功能, 並透過一定的通訊機制將它們有機地結合在一起, 對每個
 程式的設計是簡單的, 只在總控部分小心應付(其實也是蠻簡單的), 就可
 完成整個程式的施工.
 3.互不干擾
 這個特點是的特點, 各個程式是獨立的, 不會串位.
 4.事務化
 比如在一個資料電話查詢系統中, 將成一個程式只處理一次
 查詢即可, 即完成一個事務. 當電話查詢開始時, 產生這樣一個程式對付
 這次查詢; 另一個電話進來時, 主控程式又產生一個這樣的程式對付, 每
 個程式完成查詢任務後消失. 這樣的程式設計多簡單, 只要做一次查詢的程式
 就可以了.

二.常用的多程式程式設計的系統呼叫
 1.fork()
 功能:建立一個新的程式.
 語法:#include 
 #include 
 pid_t fork();
 說明:本系統呼叫產生一個新的程式, 叫子程式, 是呼叫程式的一個復
 製品. 呼叫程式叫父程式, 子程式繼承了父程式的幾乎所有的屬
 性:
 . 實際UID,GID和有效UID,GID.
 . 環境變數.
 . 附加GID.
 . 呼叫exec()時的關閉標誌.
 . UID設定位元位.
 . GID設定模式位元位.
 . 程式組號.
 . 會話ID.
 . 控制終端.
 . 當前工作目錄.
 . 根目錄.
 . 建立掩碼UMASK.
 . 檔案長度限制ULIMIT.
 . 預定值, 如優先順序和任何其他的程式預定引數, 根據種類不同
 決定是否可以繼承.
 . 還有一些其它屬性.
 但子程式也有與父程式不同的屬性:
 . 程式號, 子程式號不同與任何一個活動的程式組號.
 . 父程式號.
 . 子程式繼承父程式的檔案描述符或流時, 具有自己的一個複製
 並且與父程式和其它子程式共享該資源.
 . 子程式的使用者時間和系統時間被初始化為0.
 . 子程式的超時時鐘設定為0.
 . 子程式的訊號處理函式指標組置為空.
 . 子程式不繼承父程式的記錄鎖.
 返回值: 呼叫成功則對子程式返回0, 對父程式返回子程式號, 這也是
 最方便的區分父子程式的方法. 若呼叫失敗則返回-1給父程式,
 子程式不生成.
 例子:pid_t pid;
 if ((pid=fork())>0) {
 /*父程式處理過程*/
 }
 else if (pid==0) {
 /*子程式處理過程*/
 exit(0); /*注意子程式必須用exit()退出執行*/
 }
 else {
 printf("fork errorn");
 exit(0);
 }
 2.system()
 功能:產生一個新的程式, 子程式執行指定的命令.
 語法:#include 
 #include 
 int system(string)
 char *string;
 說明:本呼叫將引數string傳遞給一個命令直譯器(一般為sh)執行, 即
 string被解釋為一條命令, 由sh執行該命令.若引數string為一
 個空指標則為檢查命令直譯器是否存在.
 該命令可以同命令列命令相同形式, 但由於命令做為一個引數放
 在系統呼叫中, 應注意編譯時對特殊意義字元的處理. 命令的查
 找是按PATH環境變數的定義的. 命令所生成的後果一般不會對父
 程式造成影響.
 返回值:當引數為空指標時, 只有當命令直譯器有效時返回值為非零.
 若引數不為空指標, 返回值為該命令的返回狀態(同waitpid())
 的返回值. 命令無效或語法錯誤則返回非零值,所執行的命令被
 終止. 其他情況則返回-1.
 例子:char command[81];
 int i;
 for (i=1;i<8;i++) {
 sprintf(command,"ps -t tty%02i",i);
 system(command);
 }
 3.exec()
 功能:執行一個檔案
 語法:#include 
 int execl(path,arg0,...,argn,(char*)0)
 char *path,*arg0,...,*argn;

 int execv(path,argv)
 char *path,*argv[];

 int execle(path,arg0,...,argn,(char*)0,envp)
 char *path,*arg0,...,*argn,*envp[];

 int execve(path,argv,envp)
 char *path,*argv[],*envp[];

 int execvp(file,argv)
 char *file,*argv[];
 說明:這是一個系統呼叫族, 用於將一個新的程式調入本程式所佔的內
 存, 並覆蓋之, 產生新的記憶體程式映象. 新的程式可以是可執行
 檔案或批命令.
 當C程式被執行時,是如下呼叫的:
 main(int argc,char *argv[],char *envp[]);
 argc是引數個數,是各個引數字串指標陣列,envp是新程式的環
 境變數字串的指標陣列.argc至少為1,argv[0]為程式檔名,
 所以,在上面的exec系統呼叫族中,path為新程式檔案的路徑名,
 file為新程式檔名,若file不是全路徑名,系統呼叫會按PATH環
 境變數自動找對應的可執行檔案執行.若新程式檔案不是一個可
 執行的目標檔案(如批處理檔案),則execlp()和execvp()會將該
 檔案內容作為一個命令直譯器的標準輸入形成system().
 arg0,...等指標指向'結束的字串,組成新程式的有效引數,
 且該引數列表以一個空指標結束.反過來,arg0至少必須存在並指
 向新程式檔名或路徑名.
 同樣,argv是字串指標陣列,argv[0]指向新程式檔名或路徑
 名,並以一空指標結束.
 envp是一個字串指標陣列,以空指標結束,這些字串組成新進
 程的環境.
 在呼叫這些系統呼叫前開啟的檔案指標對新程式來說也是開啟的,
 除非它已定義了close-on-exec標誌.開啟的檔案指標在新程式中
 保持不變,所有相關的檔案鎖也被保留.
 呼叫程式設定並正被捕俘的訊號在新程式中被恢復為預設設定,
 其它的則保持不變.
 新程式啟動時按檔案的SUID和SGID設定定義檔案的UID和GID為有
 效UID和GID.
 新程式還繼承瞭如下屬性:
 . 附加GID.
 . 程式號.
 . 父程式號.
 . 程式組號.
 . 會話號.
 . 控制終端.
 . alarm時鐘訊號剩下的時間.
 . 當前工作目錄.
 . 根目錄.
 . 檔案建立掩碼.
 . 資源限制.
 . 使用者時間,系統時間,子程式使用者時間,子程式系統時間.
 . 記錄鎖.
 . 程式訊號掩碼.
 . 訊號遮蔽.
 . 優先順序.
 . 預定值.
 呼叫成功後,系統呼叫修改新程式檔案的最新訪問時間.
 返回值:該系統呼叫一般不會有成功返回值, 因為原來的程式已蕩然無
 存.
 例子:printf("now this process will be ps commandn");
 execl("/bin/ps","ps","-ef",NULL);
 4.popen()
 功能:初始化從/到一個程式的管道.
 語法:#include 
 FILE *popen(command,type)
 char *command,type;
 說明:本系統呼叫在呼叫程式和被執行命令間建立一個管道.
 引數command做為被執行的命令列.type做為I/O模式,"r"為從被
 執行命令讀,"w"為向被執行命令寫.返回一個標準流指標,做為管
 道描述符,向被執行命令讀或寫資料(做為被執行命令的STDIN或
 STDOUT)該系統呼叫可以用來在程式中呼叫系統命令,並取得命令
 的輸出資訊或者向命令輸入資訊.
 返回值:不成功則返回NULL,成功則返回管道的檔案指標.
 5.pclose()
 功能:關閉到一個程式的管道.
 語法:#include 
 int pclose(strm)
 FILE *strm;
 說明:本系統呼叫用於關閉由popen()開啟的管道,並會等待由popen()
 啟用的命令執行結束後,關閉管道後讀取命令返回碼.
 返回值:若關閉的檔案描述符不是由popen()開啟的,則返回-1.
 例子:printf("now this process will call popen system calln");
 FILE * fd;
 if ((fd=p0/*n("ps -ef","*/;)==NULL) {
 printf("call popen failedn");
 return;
 }
 else {
 char str[80];
 while (fgets(str,80,fd)!=NULL)
 printf("%sn",str);
 }
 pclose(fd);
 6.wait()
 功能:等待一個子程式返回並修改狀態
 語法:#include 
 #include 
 pid_t wait(stat_loc)
 int *stat_loc;
 說明:允許呼叫程式取得子程式的狀態資訊.呼叫程式將會掛起直到其
 一個子程式終止.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990833/,如需轉載,請註明出處,否則將追究法律責任。

相關文章