1、擷取進程ID[1]
每個進程都有一個唯一的正數(非0)進程ID(PID)。
範例程式碼
#include <unistd.h>#include <sys/types.h>pid t getpid(void);pid t getppid(void);returns: PID of either the caller or the parent
The getpid and getppid routines return an integer value of type pid_t, which on Linux systems
is defined in types.h as an int.
進程總是處於運行,停止,終止三種狀態間。
2、建立和終止
範例程式碼
#include <stdlib.h>void exit(int status);this function does not return#include <unistd.h>#include <sys/types.h>pid t fork(void);returns: 0 to child, PID of child to parent, -1 on error#include <sys/types.h>#include <sys/wait.h>pid t waitpid(pid t pid, int *status, int options);returns: PID of child if OK, 0 (if WNOHANG) or -1 on errorThe members of the wait set are determined by the pid argument: If pid > 0, then the wait set is the singleton child process whose process ID is equal to pid. If pid = -1, then the wait set consists of all of the parent’s child processes.
The newly created child process is almost, but not quite, identical to the parent. The child
gets an identical (but separate) copy of the parent’s userlevel virtual address space, including the text, data,
and bss segments, heap, and user stack. The child also gets identical copies of any of the parent’s open file descriptors, which
means the child can read and write any files that were open in the parent when it called fork. The most significant
difference between the parent and the newly created child is that they have different
PIDs.
fork函數常令人迷惑,因為它只被調用一次,卻會返回兩次:一次是在調用進程(父進程)中,一次是在新建立的子進程中。
樣本見原文中。
3、回收子進程
進程終止時,核心並不是立即把它從系統中清除;而是保持一種終止狀態,直到被父進程回收(reaped)。父進程回收已終止的子進程時,核心將子進程的退出狀態傳遞給父進程,然後拋棄已終止的進程。一個終止了但仍未被回收的進程稱為殭屍進程(zombie)。
如果父進程沒有回收,則通過init進程來回收。
一個進程通過調用waitpid函數來等待它的子進程終止或暫停。
4、進程休眠
範例程式碼
#include <unistd.h>unsigned int sleep(unsigned int secs);returns: seconds left to sleep//讓進程掛起一段時間#include <unistd.h>int pause(void);always returns -1//puts the calling function to sleep until a signal is received by the process.
5、載入並運行程式
範例程式碼
#include <unistd.h>int execve(char *filename, char *argv[], char *envp);does not return if OK, returns -1 on errorint main(int argc, char **argv, char **envp);int main(int argc, char *argv[], char *envp[]);
在execve載入了filename之後,啟動代碼準備棧,並將控制傳遞給新程式的主函數,函數原形如代碼中所示。
通過getenv,setenv,unsetenv來裝置環境變數。
6、進程是執行中程式的一個特殊執行個體;程式總是運行在某個進程的上下文中。fork函數在新的子進程中運行相同的程式,新的子進程是父進程的一個複製品;execve函數在當前進程的上下文中載入並運行一個新的程式,它會覆蓋當前進程的地址空間,但並沒有建立一個新進程,新的程式仍然有相同的PID,並且繼承了調用execve函數時開啟的所有檔案描述符。
範例程式碼
/* $begin shellmain */#include "csapp.h"#define MAXARGS 128/* function prototypes */void eval(char*cmdline);int parseline(char *buf, char **argv);int builtin_command(char **argv); int main() { char cmdline[MAXLINE]; /* command line */ while (1) {/* read */printf("> "); Fgets(cmdline, MAXLINE, stdin); if (feof(stdin)) exit(0);/* evaluate */eval(cmdline); } }/* $end shellmain */ /* $begin eval *//* eval - evaluate a command line */void eval(char *cmdline) { char *argv[MAXARGS]; /* argv for execve() */ char buf[MAXLINE]; /* holds modified command line */ int bg; /* should the job run in bg or fg? */ pid_t pid; /* process id */ strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) return; /* ignore empty lines */ if (!builtin_command(argv)) { if ((pid = Fork()) == 0) { /* child runs user job */ if (execve(argv[0], argv, environ) < 0) {printf("%s: Command not found.\n", argv[0]);exit(0); }}/* parent waits for foreground job to terminate */if (!bg) { int status; if (waitpid(pid, &status, 0) < 0)unix_error("waitfg: waitpid error");}else printf("%d %s", pid, cmdline); } return;}/* if first arg is a builtin command, run it and return true */int builtin_command(char **argv) { if (!strcmp(argv[0], "quit")) /* quit command */exit(0); if (!strcmp(argv[0], "&")) /* ignore singleton & */return 1; return 0; /* not a builtin command */}/* $end eval *//* $begin parseline *//* parseline - parse the command line and build the argv array */int parseline(char *buf, char **argv) { char *delim; /* points to first space delimiter */ int argc; /* number of args */ int bg; /* background job? */ buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */ while (*buf && (*buf == ' ')) /* ignore leading spaces */buf++; /* build the argv list */ argc = 0; while ((delim = strchr(buf, ' '))) {argv[argc++] = buf;*delim = '\0';buf = delim + 1;while (*buf && (*buf == ' ')) /* ignore spaces */ buf++; } argv[argc] = NULL; if (argc == 0) /* ignore blank line */return 1; /* should the job run in the background? */ if ((bg = (*argv[argc-1] == '&')) != 0)argv[--argc] = NULL; return bg;}/* $end parseline */
<Computer Systems:A Programmer's Perspective>
註:[1] 原書8.4節有詳細的論述。