QThread的用法:开启与退出

本文介绍了QThread的两种主要使用方式之一:通过继承QThread并在run函数中实现子线程的方法。详细讲述了如何在run函数中设置事件循环及使用QTimer,并提供了启动和终止线程的代码示例。

QThread有两种用法,

一、用moveToThread()将功能类移入到线程QThread中,这个用法可以参照这篇博客:http://blog.youkuaiyun.com/lynfam/article/details/7081757,文章讲的深入浅出,层层递进,非常值得一读; 
二、还有一种方法就是继承QThread,在run函数中实现子线程,本文主要是讲这种方法的注意事项。

QThread::run()是子线程的入口函数,子线程的所有变量都需要在run()函数中声明与定义。为了实现子线程的循环运行,可以用两种方法:1、用while()循环,实现子线程的重复运行;2、在run()函数中实现事件循环。 
方法1就是主要用于轮询或周期处理功能,代码实现简单,这里就不再介绍, 
方法2需要在run()函数中实现事件循环,同时退出时还需要清理线程内容,下面就用代码演示一下。

void GSPChannel::run()
{
    QTimer timer;
    bool res = connect(&timer,SIGNAL(timeout()),gspProcess,SLOT(SlotTimeOut()),Qt::DirectConnection);
    timer.start(GSP_TIME_CYC);

    exec();
    return;
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在run()函数中调用exec()就可以在子线程中实现了事件循环,这样子线程也拥有了自己的事件循环机制,QTimer就是在子线程中运行了。 
子线程的启动如下

GSPChannel* channel = new GSPChannel(handle,ipaddr);
channel->start();
 
  • 1
  • 2

子线程从start()函数开始执行,即开始运行run()函数。

在运行结束后,需要中止子线程时用如下代码

channel->quit();
channel->wait();
delete channel;
 
  • 1
  • 2
  • 3

注意:quit()函数是用来停止QThread的,但是由于Qt本身是事件循环机制,所以在调用完quit()后,QThread可能还没有完全停止,此时如果执行delete channel,程序就会报错。在执行quit()后,调用wait()来等待QThread子线程的结束(即从run()函数的返回),这样就能保证在清除QThread时,其子线程是停止运行的。

<think>我们正在分析用户提供的C++代码片段:QFuture<int>f=QtConcurrent::run(&Test::getCount,&test,4);目标:深入理解QtConcurrent::run、QFuture和QFutureWatcher的使用,以及多线程环境下的线程标识输出。我们将按照以下步骤解析:1.分解代码:解释每个部分的作用2.解释QtConcurrent::run的工作原理3.说明QFuture的作用4.介绍QFutureWatcher的用途和典型用法5.讨论线程标识输出的意义6.分析在信号槽中处理结果时的线程安全问题注意:用户之前的问题中提到了一个代码片段和一个序列图,以及一些使用场景和错误处理。我们将重点放在解析给定的代码行,并扩展到整个异步任务的执行流程。</think>### 深入解析 QtConcurrent::run QFuture 机制 #### 一、代码核心解析 ```cpp QFuture<int> f = QtConcurrent::run(&Test::getCount, &test, 4); ``` 1. **QtConcurrent::run 分解** - **功能**:在 Qt 全局线程池中异步执行任务 - **参数解析**: - `&Test::getCount`:成员函数指针(需返回 `int` 类型) - `&test`:目标对象实例(必须是有效对象) - `4`:传递给函数的整型参数 - **线程模型**: - 任务在后台线程执行(非主线程) - 使用 Qt 内置线程池管理资源[^1] 2. **QFuture 作用** - **功能**:异步任务句柄,提供: - 任务状态查询:`isStarted()`, `isFinished()` - 结果获取:`result()`, `resultCount()` - 异常捕获:任务中的异常在调用 `result()` 时抛出 - **模板参数**:`<int>` 对应函数返回值类型 3. **QFutureWatcher 监控机制** ```cpp QFutureWatcher<int> w; w.setFuture(f); // 绑定异步任务 ``` - **信号机制**: ```cpp QObject::connect(&w, &QFutureWatcher<int>::finished, [&]{ qDebug() << "[线程ID] " << QThread::currentThreadId(); qDebug() << "结果值: " << f.result(); }); ``` - **关键信号**: - `finished`:任务完成时发射 - `progressValueChanged`:进度更新时发射 - **线程安全特性**: - 信号在主线程触发(即使任务在后台线程执行)[^1] - `f.result()` 在槽函数中调用是线程安全的 #### 二、线程行为分析 ```mermaid sequenceDiagram 主线程->>Qt线程池: 提交任务(getCount) Qt线程池->>工作线程: 分配执行任务 工作线程->>QFuture: 存储结果(异步) QFutureWatcher->>主线程: 发射finished信号 主线程->>槽函数: 处理结果(安全访问) ``` 1. **线程标识关键点**: - **任务执行线程**:`QThread::currentThreadId()` 在 `getCount()` 内输出工作线程 ID - **结果处理线程**:槽函数中的 `QThread::currentThreadId()` 输出主线程 ID - **跨线程通信**:通过信号槽自动完成线程切换 2. **内存安全机制**: - 对象生命周期:`test` 对象必须存活至任务完成 - 参数传递:参数 `4` 按值传递(避免引用失效) - Lambda 捕获:`[&]` 需确保捕获对象有效 #### 三、典型应用场景 1. **耗时计算任务** ```cpp // 图像处理示例 QFuture<QImage> result = QtConcurrent::run(&Processor::render, &processor, scene, 1024); ``` 2. **批量数据处理** ```cpp // 并行处理列表项 QFuture<void> tasks = QtConcurrent::map(dataList, &Data::process); ``` 3. **带进度反馈的任务** ```cpp connect(&watcher, &QFutureWatcher<void>::progressValueChanged, [](int value) { progressBar->setValue(value); // 主线程更新UI }); ``` #### 四、错误处理最佳实践 ```cpp try { int r = f.result(); // 可能抛出任务中的异常 } catch (const std::exception& e) { qCritical() << "任务失败:" << e.what(); } ``` - **异常传递**:任务中的异常通过 `QFuture::result()` 重新抛出 - **安全调用点**:必须在 `finished` 信号触发后调用 #### 五、性能优化建议 1. **线程池配置**: ```cpp QThreadPool::globalInstance()->setMaxThreadCount(8); ``` 2. **任务拆分**: ```cpp QFuture<void> task1 = QtConcurrent::run(taskA); QFuture<void> task2 = QtConcurrent::run(taskB); QFutureSynchronizer<void> sync; // 自动等待所有任务 sync.addFuture(task1); sync.addFuture(task2); ``` > **关键结论**:该模式通过分离计算线程结果处理线程,在保证线程安全的前提下最大化利用多核资源[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值