Windows 系列 -- 线程宝藏

简介

两个 part:宝藏(Windows),备忘(标准库)。

挖宝

可提醒 IO 的产物

1
2
3
// read file
ReadFileEx(hFile, ..., APCCallback); // 线程 A 发起异步请求, 并立即返回
SleepEx(INFINITE, TRUE); // APCCallback 会在线程 A 中处理

这就是 Windows 提供的异步 IO 操作之一,即: 可提醒 IO 。当然,更优雅的 IOCP 不在本文讨论范围。

问题来了,ReadFileEx 是如何做到异步回调的呢?答案:QueueUserAPC。

  • QueueUserAPC 怎么用?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    auto g_running = true;

    void ShutdownThread(); // g_running = false;

    void WorkerThread(){
    while(g_running){ SleepEx(INFINITE, TRUE); }
    }

    // 通知线程终止
    QueueUserAPC(ShutdownThread, hWorkerThread, (ULONG_PTR)Params);
    是否有很多问号?自行 deepseek, 心领神会后才能感受到它的强大:高效,简洁,安全。

Windows 线程池

根据不同用途,有多类线程池对象:I/O,等待,定时器,工作项等多种场景。

  • I/O 线程池 :踩一脚
    有价值的应用场景:文件批处理,并主动等待操作完成。大多数情况下,有更优的解决方案:可提醒 IO,IOCP等。
    1
    2
    3
    4
    5
    6
    7
    8
    CreateFile();
    CreateThreadpoolIo();
    // 批处理对:开始xN
    StartThreadpoolIo();
    WriteFile();
    // 批处理对:结束xN
    Sleep(); // 必须阻塞式等待文件操作完成
    CLoseHanle();
  • 等待线程池 :点个赞
    比较轻便的工具,即:在未来某个时刻触发回调(超时或主动触发)。
    1
    2
    3
    4
    5
    CreateEvent();
    CreateThreadpoolWait();
    SetThreadpoolWait();
    ...
    SetEvent(); //未来某个时刻,主动触发等待回调
  • 定时器线程池 : 点个赞
    比较轻便的工具,即:异步执行周期性任务。
    1
    2
    3
    4
    5
    6
    CreateThreadpoolTimer();
    SetThreadpoolTimer(); // 开始 timer 监控
    ...
    SetThreadpoolTimer(timer, NULL, 0, 0); // 停止 timer 监控
    WaitForThreadpoolTimerCallbacks(timer, TRUE); // 等待执行中任务完成,并取消待执行的任务
    CloseThreadpoolTimer(timer);
  • 工作项线程池 : 点赞
    最常用,最实用,且支持定制:线程池容量,线程优先级。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 简单场景: 默认线程池,默认优先级
    CreateThreadpoolWork(); // pool
    SubmitThreadpoolWork();
    ...
    WaitForThreadpoolWorkCallbacks(); // 等待完成或取消
    CloseThreadpoolWork(); // 清理工作项

    // 复杂场景:定制线程池
    SetThreadpoolCallbackPriority(); // 设置优先级
    SetThreadpoolThreadMaximum(); // 指定线程池容量上限
    SetThreadpoolThreadMinimum(); // 指定线程池容量下限
    SetThreadpoolCallbackPool();// 指定线程池
    线程池优先级,常用的有:THREAD_PRIORITY_IDLE(-15),THREAD_PRIORITY_NORMAL(0) 等。

备忘录

标准库提供的一些基础能力,适用于常规的业务开发。简单列一下:

  • std::async: 高易用,低控制

    1
    2
    3
    4
    5
    // 1、wrapper
    auto result = std::async(func, placeholder_1, ...); // -> std::future<>

    // 2、block until
    auto value = result.get();
  • std::packaged_task: 中等易用,可控制线程与执行时机。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 1、wrapper a callable object
    std::packaged_task<int()> task(std::launch::deferred, func); // int func(){}

    // 2、get the future
    auto result = task.get_future(); // -> std::future<>

    // 3、move to one specific thread
    std::thread t(std::move(task));

    // 4、lazy
    auto value = result.get(); // block until ...
    std::cout << "the result value is: " << value << std::endl;
  • std::promise: 较低易用,更高控制权

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 1、promise-future pair
    std::promise<int> promise;
    auto future = promise.get_future();

    // 2、move promise to the threaded func
    std::thread t(func, std::move(promise));

    try{
    // 3、block util
    auto value = future.get();
    std::cout << "the result value is: " << value << std::endl;
    } catch(std::exception& e){
    // do something
    }

从日常“琐碎的业务”来看,不怎么好用喽:非响应式,需要阻塞。如果能够动态监听 std::future 的状态,那就很棒了,比如:QFutureWatcher


Windows 系列 -- 线程宝藏
https://jalencui.com/2025/10/13/Windows-ThreadUtil/
Author
Jalen Cui
Posted on
October 13, 2025
Licensed under