Win32编程

3、进程与线程

1、课程目标

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

2、名词解释

术语英文说明
进程Process程序的运行实例
线程Thread进程中的执行单元
PIDProcess ID进程标识符
TIDThread 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