Linux和Unix一樣,有一個虛擬記憶體系統,能夠把程式碼和資料以記憶體頁面的形式放到硬碟的一個地區中,所以
Linux可以管理的進程比實體記憶體所能容納的要多得多。
進程表
查看進程
ps -ef
TTY 一列顯示了進程是從那個終端啟動的。TIME一列是進程到目前為止所佔用的CPU時間。
CMD一列顯示啟動進程使用的命令。STAT一列用來表明進程的當前代碼。
STAT代碼解釋:
S 睡眠,通常是等待某事件發生,如訊號或有輸入可用
R 運行,嚴格來說是可運行,即在運行隊列當中,處於正在執行或即將執行狀態
D 不可中斷睡眠(等待)。通常是在等待輸入輸出完成
T 停止。
Z 殭屍進程
N 低優先順序任務
W 分頁(不適用於2.6開始的版本)
s 進程會話期首進程
+ 進程屬於前台進程組
l 多線程進程
< 高優先順序進程
啟動新進程
#include<stdlib.h>
int system(const char *string);
system函數的作用是,運行以字串參數的形式傳遞給它的命令並等待該命令的完成。命令的執行情況就如同在
shell中執行下列命令
$ sh -c string
1.替換進程映像
#include<unistd.h>int execl(const char *path, const char *arg0 , ... , (char *)0);int execlp(const char *file , const char *arg0, ... , (char *)0);int execle(const char *path , const char *arg0 , ... , (char *)0 , char *const envp[] );int execv(const char *path, const char *arg0 , ... , (char *)0);int execvp(const char *file , const char *arg0, ... , (char *)0);int execve(const char *path , const char *arg0 , ... , (char *)0 , char *const envp[] );
這些函數可以分為兩類,execl,execlp和execle的參數個數是可變的,參數以一個null 指標結構結束。
以字母P結尾的函數通過搜尋path環境變數來尋找程式的可執行檔的路徑。
2.複製進程映像
#include<sys/types.h>#include<unistd.h>pid_t fork(void);
子進程中的fork調用返回的是0,父子進程可以通過這一點來判斷究竟誰是父進程,誰是子進程。
經過fork調用後,父進程返回一個新的進程PID,子進程返回0。
#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(){ pid_t pid; char *message; int n; printf("fork program starting\n"); pid = fork(); switch(pid) { case -1: perror("fork failed"); exit(1); case 0: message = "This is the child"; n = 5; break; default: message = "This is the parent"; n = 3; break; } for(; n > 0; n--) { puts(message); sleep(1); } exit(0);}
等待一個進程
#include<sys/types.h>#include<sys/wait.h>pid_t wait(int *stat_loc);
wait系統調用將父進程知道它的子進程結束為止。這個調用返回子進程的PID,它通常是已經結束啟動並執行子進程的PID。
我們可以用sys/wait.h檔案定義的宏來解釋狀態資訊。如表11-2所示
宏 說明
WIFEXITED(stat_val) 如果子進程正常結束,它就取一個非零值。
WEXITSTATUC(stat_val) 如果WIFEXITED非零,它就返回子進程的退出碼。
WIFSIGNALED(stat_val) 如果子進程因為一個未捕獲的訊號而終止,它就取一個非零值。
WTERMSIG(stat_val) 如果WIFSIGNALED非零,它返回一個訊號代碼。
WIFSTOPPED(stat_val) 如果子進程意外終止,它就取一個非零值。
WSTOPSIG(stat_val) 如果WIFSTOPPED非零,它返回一個訊號代碼
#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(){ pid_t pid; char *message; int n; int exit_code; printf("fork program starting\n"); pid = fork(); switch(pid) { case -1: exit(1); case 0: message = "This is the child"; n = 5; exit_code = 37; break; default: message = "This is the parent"; n = 3; exit_code = 0; break; } for(; n > 0; n--) { puts(message); sleep(1); }/* This section of the program waits for the child process to finish. */ if(pid) { int stat_val; pid_t child_pid; child_pid = wait(&stat_val); printf("Child has finished: PID = %d\n", child_pid); if(WIFEXITED(stat_val)) printf("Child exited with code %d\n", WEXITSTATUS(stat_val)); else printf("Child terminated abnormally\n"); } exit (exit_code);}
殭屍進程
用fork來建立進程確實很有用,但你必須清楚子進程的運行情況。子進程終止時,它與父進程之間的關聯還會保持。
直到父進程也正常終止或父進程調用wait才告結束。因此,進程表中代表子進程的表項不會立刻釋放。雖然子進程
已經不再運行,但它依然存在系統中,因為它的退出碼還需要儲存起來,以備父進程今後的wait調用使用。這時它
成為一個死進程或殭屍進程。
還有一個系統調用可以用來等待子進程的結束,它是waitpid函數。你可以用它來等待某個特定的進程結束。
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc , int options);
輸入輸出重新導向
#include <stdio.h>#include <ctype.h>#include <stdlib.h>int main(){ int ch; while((ch = getchar()) != EOF) { putchar(toupper(ch)); } exit(0);}
/* This code, useupper.c, accepts a file name as an argument and will respond with an error if called incorrectly. */#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(int argc, char *argv[]){ char *filename; if(argc != 2) { fprintf(stderr, "usage: useupper file\n"); exit(1); } filename = argv[1];/* That done, we reopen the standard input, again checking for any errors as we do so, and then use execl to call upper. */ if(!freopen(filename, "r", stdin)) { fprintf(stderr, "could not redirect stdin to file %s\n", filename); exit(2); } execl("./upper", "upper", 0);/* Don't forget that execl replaces the current process; provided there is no error, the remaining lines are not executed. */ perror("could not exec ./upper"); exit(3);}
freopen()函數負責把一個流重新導向到另外一個流。