Windows 系列 -- 线程宝藏
简介
两个 part:宝藏(Windows),备忘(标准库)。
挖宝
可提醒 IO 的产物
1 |
|
这就是 Windows 提供的异步 IO 操作之一,即: 可提醒 IO 。当然,更优雅的 IOCP 不在本文讨论范围。
问题来了,ReadFileEx 是如何做到异步回调的呢?答案:QueueUserAPC。
- QueueUserAPC 怎么用?是否有很多问号?自行 deepseek, 心领神会后才能感受到它的强大:高效,简洁,安全。
1
2
3
4
5
6
7
8
9
10auto g_running = true;
void ShutdownThread(); // g_running = false;
void WorkerThread(){
while(g_running){ SleepEx(INFINITE, TRUE); }
}
// 通知线程终止
QueueUserAPC(ShutdownThread, hWorkerThread, (ULONG_PTR)Params);
Windows 线程池
根据不同用途,有多类线程池对象:I/O,等待,定时器,工作项等多种场景。
- I/O 线程池 :踩一脚
有价值的应用场景:文件批处理,并主动等待操作完成。大多数情况下,有更优的解决方案:可提醒 IO,IOCP等。1
2
3
4
5
6
7
8CreateFile();
CreateThreadpoolIo();
// 批处理对:开始xN
StartThreadpoolIo();
WriteFile();
// 批处理对:结束xN
Sleep(); // 必须阻塞式等待文件操作完成
CLoseHanle(); - 等待线程池 :点个赞
比较轻便的工具,即:在未来某个时刻触发回调(超时或主动触发)。1
2
3
4
5CreateEvent();
CreateThreadpoolWait();
SetThreadpoolWait();
...
SetEvent(); //未来某个时刻,主动触发等待回调 - 定时器线程池 : 点个赞
比较轻便的工具,即:异步执行周期性任务。1
2
3
4
5
6CreateThreadpoolTimer();
SetThreadpoolTimer(); // 开始 timer 监控
...
SetThreadpoolTimer(timer, NULL, 0, 0); // 停止 timer 监控
WaitForThreadpoolTimerCallbacks(timer, TRUE); // 等待执行中任务完成,并取消待执行的任务
CloseThreadpoolTimer(timer); - 工作项线程池 : 点赞
最常用,最实用,且支持定制:线程池容量,线程优先级。线程池优先级,常用的有:THREAD_PRIORITY_IDLE(-15),THREAD_PRIORITY_NORMAL(0) 等。1
2
3
4
5
6
7
8
9
10
11
12// 简单场景: 默认线程池,默认优先级
CreateThreadpoolWork(); // pool
SubmitThreadpoolWork();
...
WaitForThreadpoolWorkCallbacks(); // 等待完成或取消
CloseThreadpoolWork(); // 清理工作项
// 复杂场景:定制线程池
SetThreadpoolCallbackPriority(); // 设置优先级
SetThreadpoolThreadMaximum(); // 指定线程池容量上限
SetThreadpoolThreadMinimum(); // 指定线程池容量下限
SetThreadpoolCallbackPool();// 指定线程池
备忘录
标准库提供的一些基础能力,适用于常规的业务开发。简单列一下:
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/