行程

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

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

名稱

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

概念

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

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

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

2.1 內容

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

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

2.2 狀態

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

新生（new）：行程新產生中。
執行（running）：正在執行。
等待（waiting）：等待某事發生，例如等待使用者輸入完成。亦稱 “阻塞”（blocked）
就緒（ready）：排班中，等待 CPU。
結束（terminated）：完成執行。

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

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

2.3 行程控制表

2.4 執行緒

2.5 排程

行程間通訊（Inter-process communication）

Unix 程序

Windows 程序

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

OpenProcess (PROCESSALLACCESS, TRUE, procId); // 或者 PROCESSQUERYINFORMATION

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

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

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

include

void main {

STARTUPINFO si;

PROCESS_INFORMATION pi;

ZeroMemory (&si, sizeof (si));

si.cb = sizeof (si);

ZeroMemory (&pi, sizeof (pi));

// Start the child process.

if (!CreateProcess (NULL, // No module name (use command line)

"demo.exe arg1", // Command line

NULL, // Process handle not inheritable

NULL, // Thread handle not inheritable

FALSE, // Set handle inheritance to FALSE

0, // No creation flags

NULL, // Use parent's environment block

NULL, // Use parent's starting directory

&si, // Pointer to STARTUPINFO structure

&pi) // Pointer to PROCESS_INFORMATION structure, 用於給出子程序主視窗的屬性

) {printf ("CreateProcess failed (% d).\n", GetLastError );

return;

}

// Wait until child process exits.

WaitForSingleObject (pi.hProcess, INFINITE);

// Close process and thread handles.

CloseHandle (pi.hProcess);

CloseHandle (pi.hThread);

}

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

CreateFile 返回的開啟控制代碼，包括檔案、控制檯輸入緩衝區、控制檯螢幕緩衝區，命名管道，序列埠通訊裝置，郵槽.

開啟的控制代碼，包括：程序、執行緒、互斥鎖、事件物件、訊號量、命名管道、匿名管道、檔案對映物件。
環境變數
當前目錄
控制檯，除非程序脫離（detach）或建立了新的控制檯。
錯誤模式，使用 API 函式 SetErrorMode 設定
程序親和掩碼（affinity mask），用以指示期望使用 CPU 的哪些核
在哪個作業中。

子程序不能繼承：

優先順序類別 Priority class.

控制代碼，由 LocalAlloc, GlobalAlloc, HeapCreate, HeapAlloc 返回
偽控制代碼，由 GetCurrentProcess 或 GetCurrentThread 返回
DLL 模組控制代碼，由 LoadLibrary 返回
GDI 物件控制代碼或 USER 物件控制代碼，如 HBITMAP 或 HMENU.

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

下述 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，一個程序的所有模組的控制代碼。示例如下：

PROCESSENTRY32 pe32;

HANDLE hSnaphot;

HANDLE hApp;

DWORD dProcess;

hSnaphot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); // 獲取程序快照

Process32First (hSnaphot, &pe32); // 列舉第一個程序

do {if (lstrcmpi (pe32.szExeFile, _T ("NotePad.exe")) == 0) { // 查詢程序名稱為 NotePad.exe

dProcess = pe32.th32ProcessID;

break;

}

} while (Process32Next (hSnaphot, &pe32)); // 不斷迴圈直到列舉不到程序

hApp = OpenProcess (PROCESSVMOPERATION | SYNCHRONIZE, FALSE, dProcess); // 根據程序 ID 獲取程式的控制代碼

if (!WaitForSingleObject (hApp, INFINITE)) // 等待程序關閉

AfxMessageBox ("記事本已經關閉！");

// 另一種方法

DWORD aProcId1024, dwProcCnt, dwModCnt;

HMODULE hMod1000;

TCHAR szPathMAX_PATH;

// 枚舉出所有程序 ID

if (!EnumProcesses (aProcId, sizeof (aProcId), &dwProcCnt)) {

//cout

相關

時間片
程序樹