第四章 抽象:進程
將程序的運行抽象爲一個進程,使多個進程可以併發執行。
虛擬化CPU提供假象:有多個CPU
現在的CPU都是多核多線程的,也就是說,可以線程之間可以並行執行。
注:線程和進程的區別:起初是單CPU時代,程序的每次運行都會進行資源的分配,這時候,進程就是分配資源的最小單位;同時,單CPU時代,也沒有引入線程的概念,所以,那時候,進程也是調度的最小單位。當進入多CPU多線程的時候,引入了線程:線程是最小的調度單位。所以,現在的進程是一個資源分配的最小單位,線程是調度的最小單位,一個進程的資源可以被多個線程共享 接下來的討論,都是在單CPU的情況下,也就是沒有線程的概念,進程也是參與調度的單位
即使是現在有了多線程,可以讓多個進程的線程並行,但是,可以看到,即使每個進程只有一個線程,運行着的線程也遠遠的多於CPU提供的線程數。
因此,我們進行虛擬化,提供有更多CPU(線程)的假象。辦法就是通過時間片的輪轉,每個進程(線程)運行一段時間,然後切換到下一個進程(線程)。
進程狀態
首先來討論理論上必需的三種狀態:
- 運行:進程正在佔用CPU
- 就緒:進程具備運行的所有資源,等待被調度
- 阻塞:進程需要請求資源,如I/O請求。
三態轉換
操作系統實現了多種狀態
除了必需的三種狀態,除了這些,進程也會處於初始狀態(進程沒有完全創建完成);
進程已退出但沒有清理的“殭屍”狀態;
有的操作系統還會有掛起操作,將進程的數據等運行時資源轉入外存,讓出內存空間,這時又會有新的狀態。
數據結構
操作系統需要一些關鍵的數據結構來跟蹤進程的星官信息。
xv6的進程信息類型:原文鏈接https://github.com/mit-pdos/xv6-public
struct context {
uint edi;
uint esi;
uint ebx;
uint ebp;
uint eip;
};
enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state
struct proc {
uint sz; // Size of process memory (bytes)
pde_t* pgdir; // Page table
char *kstack; // Bottom of kernel stack for this process
enum procstate state; // Process state
int pid; // Process ID
struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall
struct context *context; // swtch() here to run process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
};
數據結構:進程列表
爲了追蹤系統中運行的所有進程,將這些信息組織成進程列表;進程列表中的每個個體,保存一個進程的信息。這個個體結構也被稱作進程控制塊(Process Control Block, PCB)