行程(process)
什麼是行程
什麼是行程 作業系統先用一對一的「對應」將一個ELF(一種執行檔格式)映 射到記憶體中 再由作業系統依照實際的需求,擴增data session(透過brk或 mmpae等系統呼叫)及stack(自動長大) 動態連結庫(shared object, so)則由作業系統依照當時是否已經 把shared object(so)已經載入到記憶體,決定是否要載入該so或 只要將該so映射到這個行程的記憶體空間 so通常位於stack與heap之間
程式的參數 啟動行程時,可以帶上參數,這些參數如下一頁投影片所示
程式的參數 一個標準的GNU C的主程式應該下底下這樣 int main(int argc, char**argv) { int i=0; #include <unistd.h> #include <stdlib.h> while(argv[i]!=NULL) { #include <stdio.h> printf("%s\n", argv[i]); i++; /*argc,代表在呼叫這個執行檔的時候,總共 有幾個參數*/ } /*請注意,第一個參數一定是執行檔的檔名, 這樣的設計,有助於除錯*/ /*依照程式的屬性,設定適當的return value*/ /*例如在pipe中(後面張婕蕙教授),可以將 檔名當成輸出資料的一部份*/ return 1; /*argv則是字串陣列,最後一個字串是NULL*/
執行結果 $ ./echo para1 para2 para3 ./echo para1 para2 para3
程式的執行環境: 環境變數
在command模式的設定法 myname=shiwulo 注意,等號的二邊不可以加上空白字元 變數的開頭不可以是數字,變數名稱不可以是英數以外的東西,例如: @mail是不可以的 變數的內容如果有空白,可以用單引號「’」或雙引號「“」包起來 可以使用跳脫字元「\」將特殊的字元(空白、@等)加入變數 如果要附加(append)到一個變數,可以用下列形式: 例:PATH=“PATH”:myname=shiwulo 取消用unset,例如:unset myname 如果要將該變數傳給子行程,要加上export,例如:export myname
課堂作業 將你的英文名字export成環境變數 將「./」加到PATH內 試試看,如果執行目前目錄的執行檔,還需要加上「./myexe」或者 「myexe」就好 這可能會造成安全性的漏洞
user environment相關的函數及變數 #include <stdlib.h> char *getenv(const char *name); int putenv(char *string); extern char **environ;
listEnv #include <stdlib.h> #include <stdio.h> extern char **environ; int main(int argc, char**argv) { int i; while(environ[i] != NULL) { printf("%s\n", environ[i++]); }
執行結果 XDG_VTNR=7 XDG_SESSION_ID=c2 ... XDG_RUNTIME_DIR=/run/user/1000 DISPLAY=:0 XDG_CURRENT_DESKTOP=Unity GTK_IM_MODULE=ibus LESSCLOSE=/usr/bin/lesspipe %s %s TEXTDOMAINDIR=/usr/share/locale/ COLORTERM=gnome-terminal XAUTHORITY=/home/shiwulo/.Xauthority _=./listEnv
getenv #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int i; char* value; for (i=1; argv[i]!=NULL; i++) { value = getenv(argv[i]); printf("%s=%s\n", argv[i], value); } return 0;
執行結果 ./getEnv PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/g ames:/usr/local/games
程式碼的結束呼叫
程式的結束 程式結束時,作業系統會回收幾乎所有的資源,並且讓這個程式 進入殭屍模式(zombie,下一個章節會介紹)。 我們可以「註冊」一些函數,讓程式碼「正確的結束時」,將執 行這些函數。 例如:釋放shared memory 例如:釋放網路的socket
atexit #include <stdlib.h> int atexit(void (*function)(void)); int on_exit(void (*function)(int , void *), void *arg); atexit 在程式正常結束時,作業系統(OR compiler)會幫我們呼 叫函數:function on_exit在程式正常結束時,將呼叫所註冊的函數,該函數的第一 個參數是「該程式的回傳值」,第二個變數則是一個指標(使用 者可以自行應用) on_exit目前只能在Linux上使用
atexit #include <stdio.h> #include <stdlib.h> void myName() { printf("shiwulo\n"); } int main(int argc, char **argv) { atexit(myName); return 0;
執行結果 $ ./atexit shiwulo
控制行程的 優先權及多核心排程
改變行程的優先權 對大部分的系統而言(包含Linux)優先權越小,就能拿到更高的 優先權(或者是提升優先權) 例如:優先權0是系統中最高的優先權 例如:優先權139是系統最低的優先權 通常只有root可以提升優先權,其他使用者只能降低優先權 在Linux中,撰寫程式時不可以假設底層的優先權處理機制 例如:為了避免競賽問題(race condition),假設高優先權的工作做完 以後,才執行低優先權的工作。
變更優先權 Linux指令 函數呼叫 #include <unistd.h> nice 函數呼叫 #include <unistd.h> int nice(int inc); /*回傳值為先的優先權*/
myNice.c #include <stdio.h> #include <unistd.h> #include <errno.h> int main(int argc, char **argv) { int niceVal; int newNiceVal; sscanf(argv[1], "%d", &niceVal); errno =0; newNiceVal = nice(niceVal); if (newNiceVal == -1 && errno !=0) perror("nice"); else printf("new val = %d\n", newNiceVal); return 0; }
執行結果 ./myNice 10 new val = 10 shiwulo@ubuntu:~/Desktop/sp/ch9$ ./myNice -10 nice: Operation not permitted shiwulo@ubuntu:~/Desktop/sp/ch9$ sudo ./myNice -10 new val = -10
相關的巨集指令 #define _GNU_SOURCE #include <sched.h> void CPU_ZERO(cpu_set_t *set); void CPU_SET(int cpu, cpu_set_t *set); void CPU_CLR(int cpu, cpu_set_t *set); int CPU_ISSET(int cpu, cpu_set_t *set); int CPU_COUNT(cpu_set_t *set);
相關巨集的意義 CPU_ZERO() Clears set, so that it contains no CPUs. CPU_SET() Add CPU cpu to set. CPU_CLR() Remove CPU cpu from set. CPU_ISSET() Test to see if CPU cpu is a member of set. CPU_COUNT() Return the number of CPUs in set.
相關的函數 #define _GNU_SOURCE #include <sched.h> int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); int sched_getaffinity(pid_t pid, size_t cpusetsize,
cpu_set #define _GNU_SOURCE for(j=0; j<10000000; j++) { #include <sched.h> j=j+1; #include <errno.h> } #include <stdio.h> ret=sched_setaffinity(0, sizeof(cpu_set_t), &set); if (ret==-1) int main(int argc, char **argv) { perror("sched_setaffinity"); cpu_set_t set; CPU_ZERO(&set); return j; int i,j,ret; for(i=0; i<1000; i++) { CPU_SET(3, &set);
執行結果