行程

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書
「行程」的各地常用名稱
中國大陸進程
臺灣行程、過程、處理程序

行程(英語:process),是指電腦中已執行的程式,曾經是分時系統的基本運作單位。在面向處理程序設計的系統(如早期的UNIXLinux 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取得處理程序控制代碼:

 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操作的薄記資訊。
  • GetProcessMemoryInfo:取得處理程序的工作集記憶體的資訊
  • GetProcessWorkingSetSize:取得處理程序的工作集記憶體被允許的下限與上限
  • SetProcessWorkingSetSize:設定處理程序的工作集記憶體的下限與上限

處理程序終止時,所有打開的控制代碼被關閉,處理程序對象被觸發(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;

相關[編輯]

參考文獻[編輯]

  1. ^ MSDN:Terminating a Process. [2017-09-20]. (原始內容存檔於2017-09-11).