• 【QT】QtConcurrent的使用介绍,与std::thread的区别


    QtConcurrent 模块是 Qt 框架中用于简化并发编程的一部分。它提供了一系列高级API,使得开发者能够更容易地编写多线程代码,从而利用多核处理器的能力。这个模块主要围绕使用线程池来执行函数调用、运行算法或者处理数据集。QtConcurrent 的核心优势是它的简洁性,因为它隐藏了线程的创建、管理和数据同步的复杂性。

    核心功能

    QtConcurrent 包含以下几个核心功能:

    • QtConcurrent::run:用于在后台线程中运行函数或成员函数。
    • QtConcurrent::map, mapReduced, reduce:用于对集合中的元素并行执行操作。
    • QtConcurrent::filter:用于并行过滤容器中的元素。

    如何使用

    1. 简单的后台执行:使用 QtConcurrent::run 来异步执行函数。

    2. 处理集合:使用 map, reduce 等函数处理数据。

    3. 等待异步操作完成:使用 QFutureQFutureWatcher 来监控和同步异步操作的结果。

    示例代码

    下面是一些使用 QtConcurrent 模块的例子:

    1. 使用 QtConcurrent::run 执行无参函数

    假设有一个简单的函数,您希望在后台线程中运行它:

    void myFunction() {
        qDebug() << "Function running in background thread";
    }
    
    // 在某个函数中
    QFuture<void> future = QtConcurrent::run(myFunction);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    2. 使用 QtConcurrent::map 对集合应用函数

    如果您想对一个 QList 中的每个元素执行某个操作,可以使用 map

    void square(int &value) {
        value *= value;
    }
    
    // 在某个函数中
    QList<int> list = {1, 2, 3, 4, 5};
    QtConcurrent::map(list, square);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3. 使用 QtConcurrent::filter 过滤数据

    过滤数据的例子:

    bool isOdd(int value) {
        return value % 2 != 0;
    }
    
    // 在某个函数中
    QList<int> list = {1, 2, 3, 4, 5};
    QtConcurrent::filter(list, isOdd);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4. 使用 QtConcurrent::reduce 合并结果

    合并结果,如计算总和:

    int add(int x, int y) {
        return x + y;
    }
    
    // 在某个函数中
    QList<int> list = {1, 2, 3, 4, 5};
    int result = QtConcurrent::blockingReduce(list, add, 0);  // 初始值为 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意事项

    • 使用 QtConcurrent 时,需要注意线程安全和数据访问冲突。
    • 确保在 .pro 文件中加入 concurrent 配置:QT += concurrent
    • 使用 QFutureWatcher 可以监视 QFuture 的状态,如进度、完成状态等。

    QtConcurrent多线程编程提供了一个更简单、更高级的接口,极大地降低了多线程编程的难度,并能有效利用现代多核CPU的计算能力。

    题外话:

    在 Qt 中使用 qDebug() 结合 QThread::currentThread() 输出类似于 QThread(0x73ed260, name = "Thread (pooled)") 的信息时,它显示的是当前正在执行代码的线程的一些基本信息。

    这段输出具体说明了:

    1. 内存地址0x73ed260 是该线程对象在内存中的地址。
    2. 线程名称"Thread (pooled)" 表示线程的名称。这里的 “pooled” 暗示该线程是一个线程池中的线程。

    解释

    • QThread(0x73ed260, name = “Thread (pooled)”)
      • QThread:是 Qt 中用于线程操作的类。
      • (0x73ed260):这部分是该 QThread 对象的内存地址,用于唯一标识这个对象实例。
      • name = "Thread (pooled)":表示线程的名称,通常线程池中的线程会被标记为 “pooled”,表明它们是由 Qt 的线程池管理的,而不是独立创建的线程。

    线程池和 QtConcurrent

    当你使用 QtConcurrent 运行函数时,Qt 通常会利用内部的线程池(除非指定了其他线程池),这些线程池中的线程具有 “Thread (pooled)” 的标识。这是 Qt 管理线程资源和优化性能的一种方式,线程池可以复用活跃的线程,避免了频繁创建和销毁线程的开销。

    实际应用

    在多线程编程中,了解当前代码运行在哪个线程上是非常重要的,特别是在处理 GUI 更新或其他需要在特定线程(如主线程)上执行的操作时。Qt 中的 GUI 组件大多不是线程安全的,因此更新 GUI 元素通常需要确保在主线程上进行。

    如果您在使用 QtConcurrent 或其他多线程工具时需要确保某些操作返回主线程执行(比如更新用户界面),您可以使用 QMetaObject::invokeMethod 或通过信号和槽机制来安全地将操作调度回主线程。例如:

    // 例子:在主线程中安全更新 GUI
    QMetaObject::invokeMethod(this, "updateGui", Qt::QueuedConnection);
    
    • 1
    • 2

    这种方式可以保证 updateGui() 方法在主线程(通常是 GUI 线程)中被调用,从而安全地进行 UI 更新。

    std::thread

    在 Qt 和标准 C++ 中处理多线程时,QtConcurrent::runstd::thread 提供了不同的方法和功能,每种方法都有其独特的特点和最佳用途。

    QtConcurrent::run

    • 管理和简化QtConcurrent::run 是 Qt 框架提供的高级多线程接口,旨在简化线程的使用和管理。它自动处理线程的创建、执行和销毁,并使用 Qt 的内部线程池来管理线程。这减少了直接管理线程的复杂性,并优化了线程使用,因为线程池可以根据需要复用线程。
    • 集成:它与 Qt 的事件系统和信号槽机制紧密集成,可以方便地将线程执行结果与 Qt 的主事件循环结合,通过 QFutureQFutureWatcher 管理和监视异步操作。
    • 使用示例
      QtConcurrent::run(functiontimerused, &FunctionTimerUsed::UsedTimer);
      
      • 1

    std::thread

    • 标准库支持std::thread 是 C++11 标准库的一部分,提供了基本的线程功能。它允许开发者直接控制线程的创建和执行,提供了更精细的线程管理能力。
    • 灵活性:使用 std::thread,开发者可以直接控制线程的生命周期和同步机制。在某些需要精细控制线程行为的场合,这种能力非常重要。
    • 分离线程:通过调用 detach(),可以让线程在后台独立执行,这意味着线程一旦启动就与主线程分离,主线程不会等待其完成。这在某些长时间运行的操作中很有用,但同时也增加了管理分离线程的复杂性。
    • 使用示例
      std::thread threadTimerStart_7(&FunctionTimerUsed::UsedTimer, functiontimerused);
      threadTimerStart_7.detach();
      
      • 1
      • 2

    区别总结

    1. 线程管理

      • QtConcurrent::run 使用 Qt 的线程池,对于多数应用场景来说,这简化了线程的使用并优化了资源管理。
      • std::thread 提供更基础和直接的线程控制,适用于需要手动管理线程生命周期的情况。
    2. 集成与兼容性

      • QtConcurrent 与 Qt 的其他部分(如事件循环)集成良好,特别适用于 Qt 应用程序。
      • std::thread 是 C++标准的一部分,可以在任何 C++项目中使用,不依赖于 Qt。
    3. 错误处理和安全性

      • 使用 QtConcurrent 可以较容易地通过 QFuture 监视线程状态,而使用 std::thread 通常需要开发者自行处理线程同步和错误管理。

    根据具体需求选择合适的工具,如果是在 Qt 环境中并且不需要精细控制线程行为,QtConcurrent 可能是更合适的选择。如果您需要跨平台或不依赖 Qt 的解决方案,或者需要对线程有完全的控制,那么 std::thread 可能更适合。

  • 相关阅读:
    【多线程】CAS 详解
    ubuntu20.10 安装Qt5 并在 kits 设置编译环境
    IDM安装教程
    音频处理:Acon Digital Acoustica Premium Mac
    审计dvwa高难度命令执行漏洞的代码,编写实例说明如下函数的用法
    自己封装的reduce、map、foreach、filter、bind等方法
    如何免费pdf全部转化为word版
    UBOOT编译--- make xxx_deconfig过程详解(一)
    机器学习实战:Python基于KDE核密度估计进行分布估计(十六)
    冥想第五百九十四天
  • 原文地址:https://blog.csdn.net/weixin_44939430/article/details/137968929