行程

**行程**（英語：process），是指電腦中已執行的程式，曾經是分時系統的基本運作單位。在面向處理程序設計的系統（如早期的 UNIX，Linux 2.4 及更早的版本）中，是程式的基本執行實體；在面向執行緒設計的系統（如當代多數作業系統、Linux 2.6 及更新的版本）中，行程本身不是基本執行單位，而是執行緒的容器。

程式本身只是指令、資料及其組織形式的描述，相當於一個名詞，行程才是程式（那些指令和資料）的真正執行實例，可以想像說是現在進行式。若干行程有可能與同一個程式相關聯，且每個行程皆可以同步（循序）或非同步（平行）的方式獨立執行。現代電腦系統可在同一段時間內以處理程序的形式將多個程式載入到記憶體中，並藉由時間共享（或稱時分復用），以在一個處理器上表現出同時（平行性）執行的感覺。同樣的，使用多執行緒技術的作業系統或電腦架構，同樣程式的**平行**執行緒，可在多 CPU 主機或網路上真正**同時**執行（在不同的 CPU 上）。

## 名稱

* 整批系統環境，行程稱為**工作**（_jobs_）。
* 分時系統環境，行程稱為**使用者程式**（_user programs_）或**任務**（_tasks_）。
* 在多數情況，工作與行程是同義詞，但處理程序（_process_）已較為人接受

## 概念

使用者下達執行程式的命令後，就會產生行程。同一程式可產生多個行程（一對多關係），以允許同時有多位使用者執行同一程式，卻不會相衝突。

行程需要一些資源才能完成工作，如 CPU 使用時間、記憶體、檔案以及 I/O 裝置，且為依序逐一進行，也就是每個 CPU 核心任何時間內僅能執行一項行程。

處理程序與執行緒的區別：處理程序是電腦管理執行程式的一種方式，一個處理程序下可包含一個或者多個執行緒。執行緒可以理解為子處理程序。

### 內容

一個電腦系統行程包括（或者說「擁有」）下列資料：

* 那個程式的可執行機器碼的一個在記憶體的映像。
* 分配到的記憶體（通常是虛擬的一個記憶體區域）。記憶體的內容包括可執行代碼、特定於行程的資料（輸入、輸出）、呼叫堆疊、堆棧（用於儲存運行時運輸中途產生的資料）。
* 分配給該行程的資源的作業系統描述符，諸如檔案描述符（Unix 術語）或檔案控制代碼（Windows）、資料源和資料終端。
* 安全特性，諸如行程擁有者和行程的權限集（可以容許的操作）。
* 處理器狀態（內文），諸如暫存器內容、物理記憶體定址等。當行程正在執行時，狀態通常儲存在暫存器，其他情況在記憶體。

### 狀態

行程在執行時，狀態（_state_）會改變。所謂狀態，就是指行程目前的動作：

* 新生（_new_）：行程新產生中。
* 執行（_running_）：正在執行。
* 等待（_waiting_）：等待某事發生，例如等待使用者輸入完成。亦稱「阻塞」（_blocked_）
* 就緒（_ready_）：排班中，等待 CPU。
* 結束（_terminated_）：完成執行。

各狀態名稱可能隨不同作業系統而相異；對於單 CPU 系統（UP），任何時間可能有多個行程為等待、就緒，但必定僅有一個行程在執行。

注意：處理程序的各個狀態之間是不能隨意切換的，例如當處理程序執行時因 IO 操作而阻塞，當 IO 操作完成後並不會直接恢復回執行態，而是轉為就緒態等待 CPU 的排程。

### 過程控制段

### 執行緒

### 排程

## 行程間通訊（Inter-process communication）

## Unix 處理程序

## Windows 處理程序

作業系統使用處理程序 ID 來唯一標識每個處理程序。在一個處理程序內部，使用處理程序控制代碼來標識關注的每個處理程序。使用 Windows API 從處理程序 ID 取得處理程序控制代碼：

使用 API 函式：GetModuleFileNameEx 或 GetProcessImageFileName 或 QueryFullProcessImageName 查詢處理程序的 exe 檔名

使用 API 函式 GetCurrentProcess 可以取得本處理程序的偽控制代碼（值為 - 1），只能用於本處理程序的 API 函式呼叫；不能被其他處理程序繼承或複製。可用 API 函式 DuplicateHandle 獲得處理程序的真控制代碼。

使用 API 函式 CreateProcess 建立處理程序，WaitForSingleObject 可等待子處理程序的結束。例如：

建立的子處理程序可以繼承父處理程序的：

* CreateFile 返回的打開控制代碼，包括檔案、控制台輸入緩衝區、控制台螢幕緩衝區，命名管道，序列埠通信裝置，郵槽.
* 打開的控制代碼，包括：處理程序、執行緒、互斥鎖、事件物件、號誌、命名管道、匿名管道、檔案對映物件。
* 環境變數
* 當前目錄
* 控制台，除非處理程序脫離（detach）或建立了新的控制台。
* 錯誤模式，使用 API 函式 SetErrorMode 設定
* 處理程序親和遮罩（affinity mask），用以指示期望使用 CPU 的哪些核
* 在哪個作業中。

子處理程序不能繼承：

* 優先級類別 Priority class.
* 控制代碼，由 LocalAlloc, GlobalAlloc, HeapCreate, HeapAlloc 返回
* 偽控制代碼，由 GetCurrentProcess 或 GetCurrentThread 返回
* DLL 模組控制代碼，由 LoadLibrary 返回
* GDI 物件控制代碼或 USER 物件控制代碼，如 HBITMAP 或 HMENU.

為繼承控制代碼，父處理程序在建立（或者代開、複製）各種可繼承物件控制代碼時，在 SECURITY\_ATTRIBUTES 結構的 bInheritHandle 成員為 TRUE。在 CreateProcess 的 bInheritHandles 參數為 TRUE；如果要繼承標準輸入、標準輸出、標準錯誤的控制代碼，STARTUPINFO 結構的 dwFlags 成員包含 STARTF\_USESTDHANDLES 標誌位.

下述 API 的函式用於取得處理程序相關資訊：

* GetCommandLine：當前處理程序的命令列字串
* GetStartupInfo：當前處理程序被建立時的 STARTUPINFO 結構
* GetProcessVersion：取得可執行頭的版本資訊
* GetModuleFileName：取得包含了處理程序代碼的可執行檔的全路徑與檔名
* GetGuiResources：取得使用中的 GUI 物件的控制代碼數量
* IsDebuggerPresent：確定處理程序是否被除錯
* GetProcessIoCounters：取得處理程序執行的所有 I/O 操作的薄記資訊。
* GetProcessMemoryInfo：取得處理程序的工作集記憶體的資訊
* GetProcessWorkingSetSize：取得處理程序的工作集記憶體被允許的下限與上限
* SetProcessWorkingSetSize：設定處理程序的工作集記憶體的下限與上限

處理程序終止時，所有打開的控制代碼被關閉，處理程序物件被觸發（signaled）。處理程序的登出碼（exit code）或者在 ExitProcess、TerminateProcess 函式中指出，或者是 main、WinMain 函式返回值。如果處理程序由於一個致命異常（fatal exception）而終止，登出碼是這個異常值，同時處理程序的所有執行中的執行緒的登出碼也是這個異常值。

優雅地關閉其他處理程序的方法是用 RegisterWindowMessage 登記私有訊息，用 BroadcastSystemMessage 播放訊息，收到訊息的處理程序用 ExitProcess 關閉。

如果想要取得特定名字的處理程序的 ID，需要列舉所有處理程序。傳統辦法是 CreateToolhelp32Snapshot、Process32First、Process32Next 函式；也可以使用 EnumProcesses、EnumProcessModules 函式來取得所有的處理程序 ID，一個處理程序的所有模組的控制代碼。範例如下：

## 相關

* 時間片
* 處理程序樹

## 參考文獻