Presentation is loading. Please wait.

Presentation is loading. Please wait.

熊博安 教授.

Similar presentations


Presentation on theme: "熊博安 教授."— Presentation transcript:

1 熊博安 教授

2 Chapter 9 程序控制

3 單元介紹 程序 產生新的程序:fork() 等待子程序狀態轉換:wait() 將新的程式載入程序中:exec

4 程序控制 Chapter 9 9.1 程序 9.2 產生新的程序:fork() 9.3 等待子程序狀態轉換:wait()
9.4 將新的程式載入程序中:exec

5 單元簡介 本單元主要介紹Linux作業系統中最基本執行單元,程序 (Process)或者任務 (Task)的概念並且回覆以下的問題:
如何產生新的程序? 原父程序與新子程序之間的關係為何?有無先後執行順序?如何控 制先後順序? 如何載入新的程式執行檔?

6 何謂程序?程序(1/4) 電腦中的任何應用,例如遊戲、編輯器、瀏覽器等均需要 作業系統中任何工作均以程序(Process)方式存在系統中
先將程式原始碼撰寫完成 (Source Program) 編譯成電腦可以看得懂得執行檔 (Executable Binary Program) 存放於電腦的硬碟中 需要執行任務時,啟動執行檔 (Start Execution) 例如:將一個系統畫面上的圖示,用滑鼠點兩下即可啟動程式 作業系統中任何工作均以程序(Process)方式存在系統中 程式 (Program) 靜態存放於儲存媒體的【執行檔】 程序 (Process) 動態可完成計算與資料傳輸任務的【基本執行單元】

7 程序ID (Process ID, PID) 程序(2/4)
當一個新的程序誕生時,系統會給予這個程 序一個身份辨識碼(ID),即 程序ID (Process ID, PID) 數值:PID為一正整數 (1, 2, 3, …) 唯一性:每個程序的PID均為系統中唯一的 (unique) 生活例子:每位國家公民都會有一組唯一的 身分證字號 依據啟發程序的使用者與相關屬性關係,給 予程序一組有效的權限設定

8 /proc 程序(3/4) /proc 是一個虛擬檔案系統,裏面的檔案除了kcore外,其他檔案大小均為0
/proc包含執行期系統資訊(runtime system information) 系統記憶體內容、載入之裝置、硬體組態等

9 /proc 程序(4/4) /proc可以用來查詢系統動態資訊及設定系統動態參數 很多系統工具均參考此資料夾內容
lsmod 等同於 cat /proc/modules lspci 等同於 cat /proc/pci 可使用/usr/bin/procinfo工具程式瞭解系統資訊 例如:能源管理、裝置、CPU資訊、驅動程式、資安、檔案系統、中斷、I/O阜、 核心資訊等 可查看/proc/PID (PID為某個程序的ID)資料夾,瞭解某程序的相關資訊 例如:環境變數、工作資料夾、執行檔、開啟的檔案、程序狀態等

10 程序控制 Chapter 9 9.1 程序 9.2 產生新的程序:fork() 9.3 等待子程序狀態轉換:wait()
9.4 將新的程式載入程序中:exec

11 產生新的程序:fork() (1/4) POSIX 作業系統的標準中,新的程序均需藉由呼叫fork()函數而產生 fork()函數雛型
父程序(parent process):呼叫fork()函數的程序。 子程序(child process):fork()回傳後,新產生的程序。 fork()函數雛型 #include <unistd.h> pid_t fork(void); fork()功用 分工合作:父程序與一個以上的子程序,共同分工合作完成任務。 執行新程式:由子程序執行新的程式,父程序可選擇等待或不等子程序完成執行程 式。

12 產生新的程序:fork() (2/4) fork()回傳時,若成功 若fork()失敗,則回傳-1 新子程序將被加入於系統中
子程序與父程序擁有一模一樣的記憶體內容 程式機器碼、程序所有資料、程序堆疊(stack)、程序heap、環境變數等 子程序與父程序不同的屬性有:PID、資源使用率、CPU計時器、待處理號誌、應用程式 計時器 (重設) fork()回傳值 在父程序,回傳值為新子程序的PID 在子程序,回傳值為0 可做為分工合作時,不同的程式碼段落 父程序程式碼 vs. 子程序的程式碼 (在同一支程式內) 若fork()失敗,則回傳-1

13 若fork()成功,父程序與子程序均從此敘述繼續執行
fork() 程式範例 fork() (3/4) 若fork()成功,父程序與子程序均從此敘述繼續執行 #include <stdio.h> #include <unistd.h> int main() { int var = 0; pid_t pid; pid = fork(); printf(“%d”, var); if(pid == 0) { /* child 執行 */ var = 1; } else if (pid > 0) { /* parent 執行 */ var = 2; } printf(“%d”, var) return 0;

14 fork()程式範例 fork()(4/4) 利用fork()的回傳值 (亦即pid)進行父程序與子程序各自需要完成任務的 程式碼區分
各程序的執行結果: 父程序:02 子程序:01 然而,系統並沒有限制兩個程序的執行順序 若fork()成功,執行結果可能為:0012, 0021, 0102, 或 0201 若fork()失敗,執行結果為:00

15 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Lab 1: debugging fork() Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

16 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
Lab 1: debugging fork() When a program forks, gdb will continue to debug the parent process and the child process will run unimpeded. If you have set a breakpoint in any code which the child then executes, the child will get a SIGTRAP signal which (unless it catches the signal) will cause it to terminate. debugging the child process using touch commend (hint: put sleep after fork) debug child process instead of parent process (using “set follow-fork-mode child” Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

17 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
lab 1: debugging fork() $gcc -g lab1-1.c $gdb a.out (gdb)b main /*set a breakpoint*/ (gdb)r /*run*/ (gdb)n /*next*/ (gdb)s /*step into*/ (gdb)p glob /*print*/ (gdb)display glob (gdb)c /*continue*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

18 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
lab 1: debugging fork() $gcc -g lab1-1.c $gdb a.out (gdb)l main /*list 10 lines of source code of main function*/ (gdb)b main /*set a breakpoint*/ (gdb)r /*run*/ (gdb)n /*next*/ (gdb)p globvar /*print*/ (gdb)c /*continue*/ (gdb)set globvar=11 /*Setting Variables*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

19 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
lab 1: debugging fork() (gdb) set follow-fork-mode child (gdb) n ... (gdb) p pid /*child OR parent?*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

20 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
lab 1: debugging fork() (gdb) set follow-fork-mode child (gdb) n ... (gdb) p pid /*child OR parent?*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

21 Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan
lab 1: debugging fork() /*modify your program like... waiting = 1; if (fork()==0) while(waiting); ... */ $sudo gdb a.out (gdb) attach pid (gdb) set waiting=0 /*continue*/ Slides©2006 Pao-Ann Hsiung, National Chung Cheng University, Taiwan

22 程序控制 Chapter 9 9.1 程序 9.2 產生新的程序:fork() 9.3 等待子程序狀態轉換:wait()
9.4 將新的程式載入程序中:exec

23 等待子程序狀態轉換:wait() (1/7) 當子程序狀態轉換時,父程序負責處理其狀態。
子程序結束:父程序等待後,可使子程序所佔用的資源釋放還給系統。 若父程序沒有等帶子程序,子程序會變成殭屍程序(zombie process)。 子程序收到號誌後暫停運行 (stopped)。 子程序收到號誌後恢復運行 (resumed)。

24 < -1 or > 0: 指定子程序 (取絕對值)
wait() (2/7) -函數雛型 #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); /* 等待任何一個子程序結束 */ pid_t waitpid(pid_t pid, int *status, int options); /* 等待子程序 結束 */ int waitid(idtype_t idtype, id_t id, siginfo_t * infop, int options); /* 等待子程序的特定狀態轉換 */ 若非NULL,儲存子程序狀態 < -1 or > 0: 指定子程序 (取絕對值) -1: 任何子程序 0: 同群組的任何子程序 OR of { WNOHANG (若沒有子程序結束立刻回傳), WUNTRACED (回傳,若有子程序被暫停), WCONTINUED (回傳,若有子程序被恢復) }

25 等待子程序狀態轉換:wait() (3/7) 檢查子程序狀態可使用表中的MACROS,但是直接使用整數值 status,而不是指標。
描述 WIFEXITED(status) TRUE,若子程序正常結束 WEXITSTATUS(status) 子程序結束狀態 (exit status) WIFSIGNALED(status) TRUE,若子程序被號誌終止 WTERMSIG(status) 子程序被號誌終止的號誌編號 (signal number) WCOREDUMP(status) TRUE,若子程序有產生CORE檔 WIFSTOPPED(status) TRUE,若子程序被號誌暫停 WSTOPSIG(status) 子程序被號誌暫停的號誌編號 (signal number) WIFCONTINUED(status) TRUE,若子程序收到SIGCONT號誌而恢復運行

26 等待子程序狀態轉換:wait() (4/7) waitid() 的參數:idtype, id, options idtype 參數 描述
P_PID 子程序PID需要符合 id 參數值 P_PGID 子程序群組ID需要符合 id 參數值 P_ALL 任何子程序 (id 將被忽略) options 參數 描述 WEXITED 等待子程序結束 WSTOPPED 等待子程序因為收到號誌而被暫停 WCONTINUED 等待暫停的子程序因為收到SIGCONT號誌,而恢復運行

27 範例執行結果 wait()(5/7) $ ./a.out & Child PID is [1] $ kill -STOP stopped by signal 19 $ kill -CONT continued $ kill -TERM killed by signal 15 [1]+ Done ./a.out $

28 範例程式碼 wait()(6/7) #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> Int main(int argc, char *argv[]) { pid_t cpid, w; int status; cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Code executed by child */ printf("Child PID is %ld\n", (long) getpid()); if (argc == 1) pause(); /* Wait for signals */ _exit(atoi(argv[1])); }

29 範例程式碼 wait()(7/7) else { /* Code executed by parent */ do { w = waitpid(cpid, &status, WUNTRACED | WCONTINUED); if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); } if (WIFEXITED(status)) { printf("exited, status=%d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("killed by signal %d\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("stopped by signal %d\n", WSTOPSIG(status)); } else if (WIFCONTINUED(status)) { printf("continued\n"); } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit(EXIT_SUCCESS);

30 本小節課程結束

31 程序控制 Chapter 9 9.1 程序 9.2 產生新的程序:fork() 9.3 等待子程序狀態轉換:wait()
9.4 將新的程式載入程序中:exec

32 將新的程式載入程序中:exec (1/5) 父程序呼叫fork()後所產生的子 程序,一開始擁有與父程序一 模一樣的程式碼。

33 將新的程式載入程序中:exec (2/5) exec若執行成功,原本記憶體的程序資料(機器碼、資料、堆疊、heap、 環境)均被新的程式資料取代。 因為原本呼叫exec的程式已經不存在,所以exec就不會回傳。 exec若執行不成功,函數將回傳-1到原本的程式並且會設定errno全域 變數記錄錯誤情況。

34 載入程式的exec函數有六個版本,其雛型為exec (3/5)
#include <unistd.h> /* 清單版本 list (l) versions */ int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg,..., char*const envp[]); /* 向量版本 vector (v) versions */ int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *path, char*const argv[],char*const envp[]); p: (path)不指定路徑,使用系統環境變數PATH。 e: (environment)指定環境變數陣列,不參考系統environ變數。

35 將新的程式載入程序中:exec (4/5) List/vector list vector 參考PATH? NO YES
參考environ? 函數 execl() execlp() execle() execv() execvp() execvpe() 基本上,上述函數都會用到Linux系統呼叫(system call) execve() 上述表中,根據應用程式的需求可以選用不同的exec函數,例如: 執行程式時,需要特定路徑及特定環境時,就選用execle()。 執行程式時,參考系統路徑PATH、系統環境environ,則可選用execlp()或execvp()。

36 範例程式 exec (5/5) 不參考PATH,所以需要寫出絕對路徑 “/bin/ls” 。
main() { pid_t pid; char *const parmList[] = {"/bin/ls", "-l", "/u/userid/dirname", NULL}; if ((pid = fork()) == -1) perror("fork error"); else if (pid == 0) { /* child */ execv("/bin/ls", parmList); printf("Return not expected. Must be an execv error.\n"); } 不參考PATH,所以需要寫出絕對路徑 “/bin/ls” 。 參考系統環境變數 environ,所以並沒有另外輸入。 程式的參數有事先放在一個陣列中(parmlist[]) 。

37 參考資料 Simply Easy Learning, TutorialsPoint, Linux man pages: 鳥哥的私房菜

38 本小節課程結束


Download ppt "熊博安 教授."

Similar presentations


Ads by Google