Skip to content

Commit 3e88f47

Browse files
committed
增加线程池的内容,对 QThreadPool 进行使用介绍 #12
1 parent 302a53b commit 3e88f47

File tree

1 file changed

+67
-1
lines changed

1 file changed

+67
-1
lines changed

Diff for: md/详细分析/04线程池.md

+67-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ int main() {
113113
114114
> [运行](https://godbolt.org/z/h5G5hTT4a)测试。
115115
116-
117116
- 创建线程池时,指定线程数量,线程池会创建对应数量的线程。
118117
119118
- 使用 `boost::asio::post` 提交任务,任务会被添加到任务队列中。
@@ -168,6 +167,73 @@ boost::asio::post(pool, task); // 将任务加入线程池
168167
pool.join(); // 等待任务完成 (或者析构自动调用)
169168
```
170169
170+
### `QThreadPool`
171+
172+
[`QThreadPool`](https://doc.qt.io/qt-6/qthreadpool.html) 是 Qt 提供的线程池实现,它是用来管理自家的 `QThreads` 的集合。
173+
174+
```cpp
175+
#include <QCoreApplication>
176+
#include <QThreadPool>
177+
#include <QRunnable>
178+
#include <QDebug>
179+
180+
struct MyTask : public QRunnable{
181+
void run() override {
182+
qDebug() << "🐢🐢🐢🐢🐢";
183+
}
184+
};
185+
186+
int main(int argc, char *argv[]){
187+
QCoreApplication app(argc, argv);
188+
189+
QThreadPool *threadPool = QThreadPool::globalInstance();
190+
191+
// 线程池最大线程数
192+
qDebug()<< threadPool->maxThreadCount();
193+
194+
for (int i = 0; i < 10; ++i) {
195+
MyTask *task = new MyTask{};
196+
threadPool->start(task);
197+
}
198+
// 当前活跃线程数 10
199+
qDebug()<<threadPool->activeThreadCount();
200+
201+
app.exec();
202+
}
203+
```
204+
205+
`Asio.thread_pool` 不同,`QThreadPool` 采用单例模式,通过静态成员函数 `QThreadPool::globalInstance()` 获取对象实例。默认情况下,`QThreadPool` 线程池的最大线程数为当前硬件支持的并发线程数,例如在我的硬件上为 `20`,这点也和 `Asio.thread_pool` 不同。
206+
207+
`QThreadPool` 依赖于 Qt 的事件循环,因此我们使用了 `QCoreApplication`
208+
209+
而将任务添加到线程池中的做法非常古老原始,我们需要**自定义一个类型继承并重写虚函数 `run`**,创建任务对象,然后将任务对象传递给线程池的 `start` 方法。
210+
211+
在 Qt6,引入了一个 [`start`](https://doc.qt.io/qt-6/qthreadpool.html#start-1) 的重载版本:
212+
213+
```cpp
214+
template <typename Callable, QRunnable::if_callable<Callable>>
215+
void QThreadPool::start(Callable &&functionToRun, int priority)
216+
{
217+
start(QRunnable::create(std::forward<Callable>(functionToRun)), priority);
218+
}
219+
```
220+
221+
它相当于是对[`start` 原始版本](https://doc.qt.io/qt-5/qthreadpool.html#start)的:
222+
223+
```cpp
224+
void start(QRunnable *runnable, int priority = 0);
225+
```
226+
227+
> [源码](https://codebrowser.dev/qt6/qtbase/src/corelib/thread/qthreadpool.cpp.html#_ZN11QThreadPool5startEP9QRunnablei)
228+
229+
进行的一个**包装**,以支持任何的[*可调用(*Callable*)*](https://zh.cppreference.com/w/cpp/named_req/Callable)类型,而无需再繁琐的继承重写 `run` 函数。
230+
231+
```cpp
232+
threadPool->start([=]{
233+
qDebug()<<QString("thread id %1").arg(i);
234+
});
235+
```
236+
171237
## 实现线程池
172238
173239
实现一个普通的能够满足日常开发需求的线程池实际上非常简单,也只需要一百多行代码。

0 commit comments

Comments
 (0)