1. 進程是unix系統中兩個最重要的基礎抽象之一(另外一個是文件)
A process is a running program
A thread is the unit of activity inside of a process
the virtualization of memory is associated with the process, the threads all share the same memory address space
2. pid
The idle process has the pid 0
The first process that the kernel executes after booting the system, called the init process, has the pid 1
默認狀況下,內核規定一個最大的進程ID值:32768(16位有符號數)
內核使用
嚴格的線性方式爲進程分配PID,若是當前全部分配的PID值最大爲17,那麼下一次分配的PID值爲18
進程層級:每個進程(init進程除外)都是從另外一個進程引生的
Children normally belong to the same process groups as their parents
3. 運行新進程
In Unix, the act of loading into memory and executing a program image is separate from the act of creating a new process
exec system call:loads a binary program into memory, replacing the previous contents of the address space, and begins execution of the new program
fork system call:create a new process
to execute a new program in a new process :first a fork to create a new process, and then an exec to load a new binary into that process
exec系列函數中,
只有execve是系統調用,其他函數都是根據execve進行封裝的C語言庫函數
fork系統調用以後,子進程與父進程幾乎徹底相同,除了如下:
a.進程ID不一樣
b.掛起的信號被清除,並不被子進程繼承
c.父進程的文件鎖不被子進程繼承
This 「fork plus exec」 combination is frequent and simple:
pid_t pid = fork();
if (pid == -1) {
fprintf(stderr, "fork error\n");
}
/* the child */
if (pid == 0) {
const char* args[] = {"grep", NULL};
int ret = execv("bin/grep", args);
if (ret == -1) {
fprintf(stderr, "execv error\n");
exit(EXIT_FAILURE);
}
}
4. copy-on-write
早期Unix中,實現fork很是簡單,the kernel created copies of all internal data structures, duplicated the process's page table entries, and then performed a
page-by-page copy of the parent's address space into the child's new address space, 這樣拷貝實現無疑是費時的
copy-on-write是一種減少資源複製開銷的延遲策略。
若是多個用戶請求對它所擁有的資源進行讀操做,資源副本的拷貝是不須要進行的,每一個用戶只須要操做一個指向共同資源的指針便可。只要沒有用戶試圖修改這個資源,那麼副本的拷貝開銷就能夠避免。若是有一個用戶確實須要修改這個資源,那麼直到這個時候,資源才複製一份,複製的一份資源被交給須要修改的用戶,其他全部用戶繼續共享原初的資源
在虛擬內存的具體示例中,copy-on-write是之內存頁爲單位進行的。
進程的內存頁首先被標記爲 read-only and copy-on-write, 若是有進程須要修改這個內存頁,就產生頁錯誤,就在這時,內核複製該內存頁,而且內存頁的copy-on-write標記被清除。
現代機器體系結構都硬件層面上支持copy-on-write
5. exit
當一個進程終止時,內核清除它包含的全部資源:分配的內存、打開的文件、信號量等
結束一個程序最經典的方式不是顯式調用exit,而是 "falling off the end" of the program
當一個進程終止時,
內核向其父進程發送 SIGCHLD 信號。默認狀況下,該信號被忽略,父進程也能夠調用 sigaction 捕捉該信號
6. wait
#include <sys/types.h>
#include <sys/wait.h>
/* wait() returns the pid of a terminated child or −1 on error. */
pid_t wait (int *status);
pid_t waitpid (pid_t pid, int *status, int options);
當pid==-1時,waitpid等待任一子進程,等同於 wait,即 wait (&status) 等同於 waitpid (−1, &status, 0)
7. system
#define _XOPEN_SOURCE /* if we want WEXITSTATUS, etc. */
#include <stdlib.h>
int system (const char *command);
It is common to use system() to run a simple utility or shell script, often with the explicit goal of simply obtaining its return value
If command is NULL, system() returns a nonzero value if the shell /bin/sh is available, and 0 otherwise
here is a sample implementation for system():
/* my_system - sync spwans and waits for the command
* /bin/sh -c <cmd> .
*
* Return -1 on error of any sort, or the exit code from
* the launched process. Does not block or ignore any signals.
*/
int my_system(const char* cmd)
{
int status;
pid_t pid = fork();
if (pid == -1) {
fprintf(stderr, "fork error\n");
return -1;
} else if (pid == 0) {
const char* argv[4];
argv[0] = "sh";
argv[1] = "-c";
argv[2] = "cmd";
argv[3] = NULL;
execv("bin/sh", argv);
exit(-1);
}
if (waitpid(pid, &status, 0) == -1) {
return -1;
} else if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}
8. 殭屍進程
a process that has terminated but has not yet been waited upon by its parent is called a 「zombie.」
Zombie processes continue to consume system resources, although only a small percentage
若是一個父進程fork產生了子進程,那麼該父進程就必須負責wait其子進程(回收殭屍子進程的所佔資源)
若是一個父進程在終止以前沒有wait其子進程呢?
內核會視察其全部子進程,並將這些子進程掛在init進程之下(確保任何進程在任什麼時候候都有一個父進程),init進程會週期性wait其全部子進程,這些子進程最終仍是會被回收資源,而不會長期以殭屍進程形式存在
9. Users and Groups
#include <sys/types.h>
#include <unistd.h>
int setuid (uid_t uid);
int setgid (gid_t gid);
uid_t getuid (void);
gid_t getgid (void);
Each process is a member of a process group,Process groups that contain more than one process are generally implementing job control
A command on the shell such as this one:
/* one process group containing three processes */
$ cat ship-inventory.txt | grep booty | sort
10. 守護進程
A daemon is a process that runs in the background, not connecting to any controlling terminal
一般在系統啓動時開始運行,而且以root權限運行,處理系統級任務,名字後綴通常爲d
一個守護進程必須知足:a. 是init進程的子進程 b. 不容許與終端鏈接