@@ -74,11 +74,86 @@ graph TD
74
74
75
75
了解以上这些基础概念是第一步也是最后一步,随着水平的提升,对这些概念认知与理解也会逐渐提升。
76
76
77
- ## 市面上常规的线程池
77
+ ## 市面上常见的线程池
78
78
79
- 在了解了线程池的基本概念与运行逻辑后,我们不用着急就尝试实现。我们可以先来聊一聊,使用一下市面上常见的那些线程池设施 ,了解它们的使用感受,接口设计的方式。
79
+ 在了解了线程池的基本概念与运行逻辑后,我们不用着急就尝试实现。我们可以先来聊一聊,使用一下市面上常见的那些 C++ 线程池设施 ,了解它们的使用感受,接口设计的方式。
80
80
81
- 如 ** ` boost::asio::thread_pool ` ** 、** ` QThreadPool ` ** 、` PPL `
81
+ ### ` boost::asio::thread_pool `
82
+
83
+ [ ` boost::asio::thread_pool ` ] ( https://think-async.com/Asio/asio-1.11.0/doc/asio/reference/thread_pool.html ) 是 [ ` Boost.Asio ` ] ( https://www.boost.org/doc/libs/1_85_0/doc/html/boost_asio.html ) 库提供的一种线程池实现。
84
+
85
+ > Asio 是一个跨平台的 C++ 库,用于** 网络** 和低级 I/O 编程,使用 ** 现代C++** 方法为开发人员提供一致的异步模型。
86
+
87
+ 使用方法:
88
+
89
+ 1 . 创建线程池对象,自行指定或者让 Asio 自动决定线程数量。
90
+
91
+ 2 . 提交任务:通过 [ ` boost::asio::post ` ] ( https://beta.boost.org/doc/libs/1_82_0/doc/html/boost_asio/reference/post.html ) 函数模板提交任务到线程池中。
92
+
93
+ 3 . 阻塞,直到池中的线程完成任务。
94
+
95
+ ``` cpp
96
+ #include < boost/asio.hpp>
97
+ #include < iostream>
98
+
99
+ void print_task (int n) {
100
+ std::cout << "Task " << n << " is running." << std::endl;
101
+ }
102
+
103
+ int main() {
104
+ boost::asio::thread_pool pool{4}; // 创建一个包含 4 个线程的线程池
105
+
106
+ for (int i = 0; i < 10; ++i) {
107
+ boost::asio::post(pool, [i]() { print_task(i); });
108
+ }
109
+
110
+ pool.join(); // 等待所有任务执行完成
111
+ }
112
+ ```
113
+
114
+ - 创建线程池时,指定线程数量,线程池会创建对应数量的线程。
115
+
116
+ - 使用 `boost::asio::post` 提交任务,任务会被添加到任务队列中。
117
+
118
+ - 线程池中的线程会从任务队列中取出任务并执行,任务执行完毕后,线程继续取下一个任务或者休眠。
119
+
120
+ - 调用 join 方法等待所有任务执行完毕并关闭线程池(`thread_pool` 析构同样会调用它,非必要)。
121
+
122
+ 如果我们不自己指明线程池的线程数量,那么 Asio 会根据函数 [`default_thread_pool_size`](https://github.com/boostorg/asio/blob/44238d033e1503c694782925d647811380a067c2/include/boost/asio/impl/thread_pool.ipp#L53-L58) 计算并返回一个**线程池的默认线程数量**。它根据系统的硬件并发能力来决定使用的线程数,通常是硬件并发能力的两倍。
123
+
124
+ ```cpp
125
+ inline long default_thread_pool_size()
126
+ {
127
+ std::size_t num_threads = thread::hardware_concurrency() * 2;
128
+ num_threads = num_threads == 0 ? 2 : num_threads;
129
+ return static_cast<long>(num_threads);
130
+ }
131
+
132
+ thread_pool::thread_pool()
133
+ : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))),
134
+ num_threads_(detail::default_thread_pool_size())
135
+ ```
136
+
137
+ 代码很简单,就是 ` thread::hardware_concurrency() * 2 ` 而已,至于下面的判断是因为 ` std::thread::hardware_concurrency() ` 在某些特殊情况下可能返回 ` 0 ` ,例如硬件并发能力无法被检测时,那将 ` num_threads ` 设置为 2,确保线程池至少有 2 个线程。
138
+
139
+ ---
140
+
141
+ 我们的重点来到它的析构函数中:
142
+
143
+ ``` cpp
144
+ thread_pool::~thread_pool ()
145
+ {
146
+ stop ();
147
+ join ();
148
+ shutdown ();
149
+ }
150
+ ```
151
+
152
+ - ` stop ` :修改内部的标志位存在使得线程池能够识别何时需要停止接收新的任务,然后唤醒所有线程准备。
153
+
154
+ - ` join() ` :等待所有线程完成它们的工作,确保所有线程都已终止。
155
+
156
+ - ` shutdown() ` :进行最终的清理,释放资源,确保线程池的完全清理和资源的正确释放
82
157
83
158
## 实现线程池
84
159
0 commit comments