行程
特定的一个计算机程序的执行 来自维基百科,自由的百科全书
特定的一个计算机程序的执行 来自维基百科,自由的百科全书
行程(英語:process),是指電腦中已執行的程式,曾經是分時系統的基本運作單位。在面向行程設計的系統(如早期的UNIX,Linux 2.4及更早的版本)中,是程式的基本執行實體;在面向執行緒設計的系統(如當代多數作業系統、Linux 2.6及更新的版本)中,行程本身不是基本執行單位,而是執行緒的容器。
「行程」的各地常用名稱 | |
---|---|
中國大陸 | 進程 |
臺灣 | 行程、過程、處理程序 |
程式本身只是指令、數據及其組織形式的描述,相當於一個名詞,行程才是程式(那些指令和數據)的真正執行實例,可以想像說是現在進行式。若干行程有可能與同一個程式相關聯,且每個行程皆可以同步(循序)或非同步(平行)的方式獨立執行。現代電腦系統可在同一段時間內以行程的形式將多個程式載入到記憶體中,並藉由時間共用(或稱時分復用),以在一個處理器上表現出同時(平行性)執行的感覺。同樣的,使用多執行緒技術的作業系統或電腦架構,同樣程式的平行執行緒,可在多CPU主機或網絡上真正同時執行(在不同的CPU上)。
用戶下達執行程式的命令後,就會產生行程。同一程式可產生多個行程(一對多關係),以允許同時有多位用戶執行同一程式,卻不會相衝突。
行程需要一些資源才能完成工作,如CPU使用時間、記憶體、檔案以及I/O裝置,且為依序逐一進行,也就是每個CPU核心任何時間內僅能執行一項行程。
行程與執行緒的區別:行程是電腦管理執行程式的一種方式,一個行程下可包含一個或者多個執行緒。執行緒可以理解為子行程。
一個電腦系統行程包括(或者說「擁有」)下列資料:
行程在執行時,狀態(state)會改變。所謂狀態,就是指行程目前的動作:
各狀態名稱可能隨不同作業系統而相異;對於單CPU系統(UP),任何時間可能有多個行程為等待、就緒,但必定僅有一個行程在執行。
注意: 行程的各個狀態之間是不能隨意切換的,例如當行程執行時因IO操作而阻塞,當IO操作完成後並不會直接恢復回執行態,而是轉為就緒態等待CPU的排程。
作業系統使用行程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);
}
建立的子行程可以繼承父行程的:
子行程不能繼承:
為繼承控制代碼,父行程在建立(或者代開、複製)各種可繼承對象控制代碼時,在SECURITY_ATTRIBUTES結構的bInheritHandle成員為TRUE。在CreateProcess的bInheritHandles參數為TRUE;如果要繼承標準輸入、標準輸出、標準錯誤的控制代碼,STARTUPINFO結構的dwFlags成員包含STARTF_USESTDHANDLES標誌位.
下述API的函數用於取得行程相關資訊:
行程終止時,所有打開的控制代碼被關閉,行程對象被觸發(signaled)。行程的退出碼(exit code)或者在ExitProcess、TerminateProcess函數中指出,或者是main、WinMain函數返回值。如果行程由於一個致命異常(fatal exception)而終止,退出碼是這個異常值,同時行程的所有執行中的執行緒的退出碼也是這個異常值。
優雅地關閉其他行程的方法是用RegisterWindowMessage登記私有訊息,用BroadcastSystemMessage播放訊息,收到訊息的行程用ExitProcess關閉。[1]
如果想要取得特定名字的行程的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(PROCESS_VM_OPERATION | SYNCHRONIZE, FALSE, dProcess); // 根据进程 ID 获取程序的句柄
if (!WaitForSingleObject(hApp, INFINITE)) // 等待进程关闭
AfxMessageBox(" 记事本已经关闭!");
// 另一种方法
DWORD aProcId[1024], dwProcCnt, dwModCnt;
HMODULE hMod[1000];
TCHAR szPath[MAX_PATH];
// 枚举出所有进程ID
if (!EnumProcesses(aProcId, sizeof(aProcId), &dwProcCnt)) {
//cout << "EnumProcesses error: " << GetLastError() << endl;
return 0;
}
// 遍例所有进程
for (DWORD i = 0; i < dwProcCnt; ++i) {
// 打开进程,如果没有权限打开则跳过
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, aProcId[i]);
if (NULL != hProc) {
// 打开进程的第1个Module,并检查其名称是否与目标相符
if (EnumProcessModules(hProc, &hMod, 1000, &dwModCnt)) {
GetModuleBaseName(hProc, hMod, szPath, MAX_PATH);
if (0 == lstrcmpi(szPath, lpName)) {
CloseHandle(hProc);
return aProcId[i];
}
}
CloseHandle(hProc);
}
}
return 0;