linux系統編程:進程原語,linux編程進程原語
進程原語
1. 進程(Process)是電腦中的程式關於某資料集合上的一次運行活動,是系統進行資源分派和調度的基本單位,是作業系統結構的基礎。
2. 進程環境
在libc中定義的全域變數environ指向環境變數表,environ沒有包含在任何標頭檔中,所以在使用時要用extern聲明。用以下代碼可以查看當前進程的所有環境變數的資訊。
#include <stdio.h> int main(void){ extern char **environ; int i; for(i = 0; environ[i] != NULL; i++) printf("%s\n", environ[i]); return 0;}
運行結果用索引值對的形式展示環境變數的資訊。幾個常見的環境變數解釋:
PATH:可執行檔的搜尋路徑。
SHELL:當前使用的shell。
HOME:目前使用者的主目錄路徑。
3. 進程狀態
4種主要的進程狀態:運行、就緒、掛起、終止。
4. 進程原語
在liunx中使用函數fork建立新的進程。
#include <unistd.h>pid_t fork(void);
函數特點:調用一次,返回兩次。
在父進程中,返回建立的子進程的pid;在子進程中返回0;出錯,返回-1。
一個建立子進程的執行個體:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>void sys_err(char *s){ perror(s); exit(1);}int main(void){ pid_t pid; pid = fork(); if (pid < 0) sys_err("fork"); else if (pid > 0) { /* parent process */ printf("I am parent,my pid is %d, my parent pid is %d\n", getpid(), getppid()); sleep(1); //休眠1秒,防止父進程過早退出 } else { /* child process */ printf("I am child,my pid is %d, my parent pid is %d\n", getpid(), getppid()); } return 0;}//I am child, my pid is 15057, my parent pid is 15056//I am parent, my pid is 15056, my parent pid is 5292
#include <unistd.h>#include <sys/types.h> //定義了pid_t、uid_t、gid_tpid_t getpid(void); //擷取當前進程的pidpid_t getppid(void); //擷取當前進程父進程的piduid_t getuid(void); //返回實際使用者iduid_t geteuid(void); //返回有效使用者idgid_t getgid(void); //返回實際使用者組idgid_t getegid(void); //返回有效使用者組id
所有id都是正數。
父進程和子進程的關係:
1.子進程複製了父進程的PCB(除了pid)和程式碼片段以及資料區。
2.用fork建立子進程後執行的是和父進程相同的程式(但有可能執行不同的代碼分支),子進程往往要調用一種exec函數以執行另一個程式。當進程調用一種exec函數時,該進程的使用者空間代碼和資料完全被新程式替換,從新程式的啟動常式開始執行。調用exec並不建立新進程,所以調用exec前後該進程的id並未改變。
5. exec族
#include <unistd.h>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[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execve(const char *path, char *const argv[], char *const envp[]);
只需弄懂了execl的使用,其它的舉一反三了:path指出了新可執行程式的路徑,後面的arg,即是提供的參數。
使用execl函數更改程式的執行:
//show.c#include <stdio.h>int main(int argc, char **argv){ int i = 0; while(i < argc) printf("%s\n", argv[i++]); return 0;}//app.c#include <stdio.h>#include <unistd.h>#include <stdlib.h>int main(int argc, char **argv){ if(argc < 2) { fprintf(stderr, "usage:app newapp ..."); exit(1); } printf("zhangxiang\n"); //$ argv[1] zx zhangxiangDavid@126.com execl(argv[1], "zx", "zhangxiangDavid@126.com", NULL); //NULL用於指明參數列表的結束 printf("David\n"); return 0;}$ gcc show.c -o show$ gcc app.c -o app$ app showzhangxiangzxzhangxiangDavid@126.com
執行printf(“zhangxiang\n”);了後,程式的程式碼片段被替換,所以原程式的printf(“David\n”);不會被執行。
l 命令列參數列表
p 搜素file時使用path變數
v 使用命令列參數數組
e 使用環境變數數組,不使用進程原有的環境變數,設定新載入程式啟動並執行環境變數
這些函數如果調用成功則載入新的程式從啟動代碼開始執行,不再返回,如果調用出錯則返回-1,所以exec函數只有出錯的傳回值而沒有成功的傳回值。
6. wait()、waitpid()
殭屍進程::子進程退出,父進程沒有回收子進程資源(PCB),則子進程變成殭屍進程。
孤兒進程:父進程先於子進程結束,則子進程成為孤兒進程,子進程的父進程成為1號進程init進程,稱為init進程領養孤兒進程。
子進程結束後,PCB仍然滯留在記憶體。父進程可以通過子進程的PCB來獲知子進程的退出狀態:正常退出時的退出碼、不正常退出時,是被哪個訊號終止的。
#include <sys/types.h>#include <sys/wait.h>pid_t wait(int *status);
函數說明:
參數status為傳出參數,用於記錄退出狀態。
當沒有子進程退出時,wait調用會阻塞當前進程。
成功,返回子進程的pid;
失敗,返回-1;
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>int main(void){ pid_t pid, wpid; pid = fork(); if(0 == pid) { printf("in child\n"); sleep(2); printf("child exit\n"); } else if(pid > 0) { while(1) { wpid = wait(NULL); printf("in parent %d\n", wpid); sleep(1); } } else { perror("fork"); exit(1); } return 0;}//in child//child exit//in parent 27909//in parent -1//in parent -1//^c
wait()會使父進程阻塞,為了不阻塞,需使用waitpid()
#include <sys/types.h>#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
函數說明:
pid指明了需回收哪個子進程的PCB;
通過指定options的值,更改函數運行狀態。(特別地,指定WNOHANG,將不會阻塞)。
指定WNOHANG,非阻塞後。若沒有進程退出,返回0,其它同wait。
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>int main(void){ pid_t pid, wpid; pid = fork(); if(0 == pid) { printf("in child\n"); sleep(2); printf("child exit\n"); } else if(pid > 0) { while(1) { wpid = waitpid(0, NULL, WNOHANG); printf("in parent %d\n", wpid); sleep(1); } } else { perror("fork"); exit(1); } return 0;}//in parent 0//in child//in parent 0//child exit//in parent 28700//in parent -1//in parent -1//^c
CCPP Blog 目錄
著作權聲明:本文為博主原創文章,轉載,請註明出處。