行程
行程(英語:process),是電腦中已執行程式的實體。行程為曾经是分時系統的基本運作單位。在面向进程设计的系统(如早期的UNIX,Linux 2.4及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统(如当代多数操作系统、Linux 2.6及更新的版本)中,行程本身不是基本執行单位,而是執行緒的容器。程式本身只是指令、数据及其组织形式的描述,行程才是程式(那些指令和数据)的真正執行实例。若干行程有可能與同一個程式相關聯,且每個行程皆可以同步(循序)或异步(平行)的方式獨立執行。現代電腦系統可在同一段時間內以进程的形式将多個程式載入到記憶體中,並藉由時間共享(或稱时分复用),以在一個處理器上表現出同時(平行性)執行的感覺。同樣的,使用多執行緒技術(多執行緒即每一個執行緒都代表一個行程内的一个独立执行上下文)的作業系統或電腦架構,同樣程式的平行线程,可在多CPU主機或網絡上真正同時執行(在不同的CPU上)。
「行程」的各地常用名稱 | |
---|---|
中国大陸 | 进程 |
臺灣 | 處理程序、行程 |
名稱
概念
使用者下達執行程式的命令後,就會產生行程。同一程式可產生多個行程(一對多關係),以允許同時有多位使用者執行同一程式,卻不會相衝突。
行程需要一些資源才能完成工作,如CPU使用時間、記憶體、檔案以及I/O裝置,且為依序逐一進行,也就是每个CPU核心任何時間內僅能執行一項行程。
內容
一個電腦系統行程包括(或者說「擁有」)下列資料:
- 那個程式的可執行機器碼的一個在記憶體的映像。
- 分配到的記憶體(通常是虛擬的一個記憶體區域)。記憶體的內容包括可執行代碼、特定於行程的資料(輸入、輸出)、呼叫堆疊、堆棧(用於保存運行時運輸中途產生的資料)。
- 分配給該行程的資源的作業系統描述符,諸如檔案描述符(Unix術語)或檔案控制代碼(Windows)、資料源和資料終端。
- 安全特性,諸如行程擁有者和行程的權限集(可以容許的操作)。
- 處理器狀態(內文),諸如暫存器內容、物理記憶體定址等。當行程正在執行時,狀態通常儲存在暫存器,其他情況在記憶體。
狀態
行程在執行時,狀態(state)會改變。所謂狀態,就是指行程目前的動作:
- 新生(new):行程新產生中。
- 執行(running):正在執行。
- 等待(waiting):等待某事發生,例如等待使用者輸入完成。亦称“阻塞”(blocked)
- 就緒(ready):排班中,等待CPU。
- 結束(terminated):完成執行。
各狀態名稱可能隨不同作業系統而相異;对于单CPU系统(UP),任何時間可能有多個行程為等待、就緒,但必定僅有一個行程在執行。
行程控制表
執行緒
排程
行程間通訊(Inter-process communication)
Unix进程
Windows进程
操作系统使用进程ID来唯一标识每个进程。在一个进程内部,使用进程句柄来标识关注的每个进程。使用Windows API从进程ID获取进程句柄:
OpenProcess(PROCESS_ALL_ACCESS, TRUE, procId); //或者PROCESS_QUERY_INFORMATION
使用API函数:GetModuleFileNameEx或GetProcessImageFileName或QueryFullProcessImageName查询进程的exe文件名
使用API函数GetCurrentProcess可以获取本进程的伪句柄(值为-1),只能用于本进程的API函数调用;不能被其他进程继承或复制。可用API函数DuplicateHandle获得进程的真句柄。
使用API函数CreateProcess创建进程,WaitForSingleObject可等待子进程的结束。例如:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
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.
为继承句柄,父进程在创建(或者代开、复制)各种可继承对象句柄时,在SECURITY_ATTRIBUTES结构的bInheritHandle成员为TRUE。在CreateProcess的bInheritHandles参数为TRUE;如果要继承标准输入、标准输出、标准错误的句柄,STARTUPINFO结构的dwFlags成员包含STARTF_USESTDHANDLES标志位.
下述API的函数用于获取进程相关信息:
- GetCommandLine:当前进程的命令行字符串
- GetStartupInfo:当前进程被创建时的STARTUPINFO结构
- GetProcessVersion:获取可执行头的版本信息
- GetModuleFileName:获取包含了进程代码的可执行文件的全路径与文件名
- GetGuiResources:获取使用中的GUI对象的句柄数量
- IsDebuggerPresent:确定进程是否被调试
- GetProcessIoCounters:获取进程执行的所有I/O操作的薄记信息。