Win32编程

3、进程与线程

1、课程目标

  1. 理解进程和线程的基本概念
  2. 掌握进程创建和管理API
  3. 学会多线程编程
  4. 掌握进程枚举和信息获取

2、名词解释

术语 英文 说明
进程 Process 程序的运行实例
线程 Thread 进程中的执行单元
PID Process ID 进程标识符
TID Thread ID 线程标识符
线程池 Thread Pool 线程的共享池

3、使用工具

工具 用途
Process Explorer 查看进程详情
Task Manager 任务管理

4、技术原理

4.1、进程 vs 线程

特性 进程 线程
地址空间 独立 共享
资源 独立 共享
创建开销
通信 IPC 直接共享内存

5、代码实现

5.1、示例1:创建进程

#include <windows.h>
#include <stdio.h>

void CreateNewProcess() {
    STARTUPINFO si = {sizeof(si)};
    PROCESS_INFORMATION pi = {0};
    
    TCHAR cmdLine[] = TEXT("notepad.exe");
    
    BOOL success = CreateProcess(
        NULL,           // 应用程序名
        cmdLine,        // 命令行
        NULL, NULL,     // 进程/线程安全属性
        FALSE,          // 不继承句柄
        0,              // 创建标志
        NULL,           // 环境变量
        NULL,           // 当前目录
        &si, &pi
    );
    
    if (success) {
        printf("Process ID: %d\n", pi.dwProcessId);
        printf("Thread ID: %d\n", pi.dwThreadId);
        
        // 等待进程结束
        WaitForSingleObject(pi.hProcess, INFINITE);
        
        // 获取退出码
        DWORD exitCode;
        GetExitCodeProcess(pi.hProcess, &exitCode);
        printf("Exit code: %d\n", exitCode);
        
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
}

5.2、示例2:创建线程

#include <windows.h>
#include <stdio.h>

typedef struct {
    int id;
    int count;
} THREAD_PARAM;

DWORD WINAPI ThreadFunc(LPVOID lpParam) {
    THREAD_PARAM* param = (THREAD_PARAM*)lpParam;
    
    for (int i = 0; i < param->count; i++) {
        printf("Thread %d: %d\n", param->id, i);
        Sleep(100);
    }
    
    return param->id;
}

void CreateThreadDemo() {
    HANDLE threads[3];
    THREAD_PARAM params[3];
    
    for (int i = 0; i < 3; i++) {
        params[i].id = i;
        params[i].count = 5;
        
        threads[i] = CreateThread(
            NULL,           // 安全属性
            0,              // 默认栈大小
            ThreadFunc,     // 线程函数
            &params[i],     // 参数
            0,              // 立即运行
            NULL            // 线程ID
        );
    }
    
    // 等待所有线程完成
    WaitForMultipleObjects(3, threads, TRUE, INFINITE);
    
    // 获取线程退出码
    for (int i = 0; i < 3; i++) {
        DWORD exitCode;
        GetExitCodeThread(threads[i], &exitCode);
        printf("Thread %d returned: %d\n", i, exitCode);
        CloseHandle(threads[i]);
    }
}

5.3、示例3:进程枚举

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

void EnumerateProcesses() {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
    if (hSnapshot == INVALID_HANDLE_VALUE) return;
    
    PROCESSENTRY32 pe = {sizeof(pe)};
    
    if (Process32First(hSnapshot, &pe)) {
        do {
            printf("PID: %5d  Name: %ls\n", 
                   pe.th32ProcessID, pe.szExeFile);
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
}

// 根据名称查找进程
DWORD FindProcessByName(const TCHAR* name) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe = {sizeof(pe)};
    DWORD pid = 0;
    
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (_tcsicmp(pe.szExeFile, name) == 0) {
                pid = pe.th32ProcessID;
                break;
            }
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return pid;
}

5.4、示例4:线程枚举

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

void EnumerateThreads(DWORD pid) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    
    THREADENTRY32 te = {sizeof(te)};
    
    if (Thread32First(hSnapshot, &te)) {
        do {
            if (te.th32OwnerProcessID == pid) {
                printf("  TID: %d, Priority: %d\n", 
                       te.th32ThreadID, te.tpBasePri);
            }
        } while (Thread32Next(hSnapshot, &te));
    }
    
    CloseHandle(hSnapshot);
}

5.5、示例5:进程信息获取

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#pragma comment(lib, "psapi.lib")

void GetProcessInfo(DWORD pid) {
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
        FALSE, pid
    );
    
    if (!hProcess) return;
    
    // 获取进程路径
    TCHAR path[MAX_PATH];
    GetModuleFileNameEx(hProcess, NULL, path, MAX_PATH);
    printf("Path: %ls\n", path);
    
    // 获取内存信息
    PROCESS_MEMORY_COUNTERS pmc;
    GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc));
    printf("Working Set: %lld KB\n", pmc.WorkingSetSize / 1024);
    
    CloseHandle(hProcess);
}

6、课后作业

  1. 基础练习:创建多线程程序计算数学运算
  2. 进程枚举:实现类似任务管理器的进程列表
  3. 进程控制:实现进程启动/终止/挂起功能
  4. 线程池:使用Windows线程池API