行程

行程（），是指电脑中已执行的程式，曾经是分时系统的基本运作单位。在面向进程设计的系统（如早期的UNIX，Linux 2.4及更早的版本）中，是程式的基本执行实体；在面向线程设计的系统（如当代多数操作系统、Linux 2.6及更新的版本）中，行程本身不是基本执行单位，而是执行绪的容器。
程式本身只是指令、数据及其组织形式的描述，相当于一个名词，行程才是程式（那些指令和数据）的真正执行实例，可以想像说是现在进行式。若干行程有可能与同一个程式相关联，且每个行程皆可以同步（循序）或异步（平行）的方式独立执行。现代电脑系统可在同一段时间内以进程的形式将多个程式载入到记忆体中，并借由时间共享（或称时分复用），以在一个处理器上表现出同时（平行性）执行的感觉。同样的，使用多执行绪技术的作业系统或电脑架构，同样程式的平行线程，可在多CPU主机或网络上真正同时执行（在不同的CPU上）。
概念.
使用者下达执行-{}-程式的命令后，就会产生行程。同一程式可产生多个行程（一对多关系），以允许同时有多位使用者执行同一程式，却不会相冲突。
行程需要一些资源才能完成工作，如CPU使用时间、记忆体、档案以及I/O装置，且为依序逐一进行，也就是每个CPU核心任何时间内仅能执行一项行程。
进程与线程的区别：进程是计算机管理运行程序的一种方式，一个进程下可包含一个或者多个线程。线程可以理解为子进程。
内容.
一个电脑系统行程包括（或者说「拥有」）下列资料：
状态.
行程在执行时，状态（"state"）会改变。所谓状态，就是指行程目前的动作：
各状态名称可能随不同作业系统而相异；对于单CPU系统（UP），任何时间可能有多个行程为等待、就绪，但必定仅有一个行程在执行。
注意: 进程的各个状态之间是不能随意切换的，例如当进程运行时因IO操作而阻塞，当IO操作完成后并不会直接恢复回运行态，而是转为就绪态等待CPU的调度。
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可等待子进程的结束。例如：
void main() {
 STARTUPINFO si;
 PROCESS_INFORMATION pi;
 ZeroMemory(&amp;si, sizeof(si));
 si.cb = sizeof(si);
 ZeroMemory(&amp;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
 &amp;si, // Pointer to STARTUPINFO structure
 &amp;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关闭。
如果想要获取特定名字的进程的ID，需要枚举所有进程。传统办法是CreateToolhelp32Snapshot、Process32First、Process32Next函数；也可以使用EnumProcesses、EnumProcessModules函数来获取所有的进程ID，一个进程的所有模块的句柄。示例如下：
PROCESSENTRY32 pe32;
HANDLE hSnaphot;
HANDLE hApp;
DWORD dProcess;
hSnaphot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 获取进程快照
Process32First(hSnaphot, &amp;pe32); // 枚举第一个进程
do {
 if (lstrcmpi(pe32.szExeFile, _T("NotePad.exe")) == 0) { // 查找进程名称为 NotePad.exe
 dProcess = pe32.th32ProcessID;
 break;
} while (Process32Next(hSnaphot, &amp;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), &amp;dwProcCnt)) {
 //cout « "EnumProcesses error: " « GetLastError() « endl;
 return 0;
// 遍例所有进程
for (DWORD i = 0; i &lt; dwProcCnt; ++i) {
 // 打开进程，如果没有权限打开则跳过
 HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, aProcId[i]);
 if (NULL != hProc) {
 // 打开进程的第1个Module，并检查其名称是否与目标相符
 if (EnumProcessModules(hProc, &amp;hMod, 1000, &amp;dwModCnt)) {
 GetModuleBaseName(hProc, hMod, szPath, MAX_PATH);
 if (0 == lstrcmpi(szPath, lpName)) {
 CloseHandle(hProc);
 return aProcId[i];
 CloseHandle(hProc);
return 0;