QtConcurrentRun原理及应用

目录

      • 前言
      • 1 原理
      • 2 应用
      • 3 示例
      • 4 总结

前言

本文介绍了QtConcurrentRun的实现原理及应用场景,并给出了一个示例展示QtConcurrentRun如何使用。

1 原理

若要理解其实现原理,就离不开研读其源码,下面的代码摘自qtconcurrentrun.h,以带一个参数的run函数为例:

namespace QtConcurrent {

template <typename T, typename Param1, typename Arg1>
QFuture<T> run(T (*functionPointer)(Param1), const Arg1 &arg1)
{
    return (new StoredFunctorCall1<T, T (*)(Param1), Arg1>(functionPointer, arg1))->start();
}

......
}//namespace QtConcurrent

从上面的代码可以看出 QtConcurrent 是一个命名空间(namespace),run 是该命名空间下的一组模板函数,最多支持5个函数参数,用于在后台线程中执行函数或Lambda表达式。接下来继续查看StoredFunctorCall1的实现,如下:

template <typename FunctionPointer, typename Arg1>
struct StoredFunctorCall1<void, FunctionPointer, Arg1>: public RunFunctionTask<void>
{
    inline StoredFunctorCall1(FunctionPointer _function, const Arg1 &_arg1)
      : function(_function), arg1(_arg1) {}
    void runFunctor() override { function(arg1); }
    FunctionPointer function;
    Arg1 arg1;
};

通过上面的代码可以看到我们调用QtConcurrent::run运行的函数 QFuture future = QtConcurrent::run(fn); fn 被保存在 StoredFunctorCall1的成员 function 中,参数保存到成员 arg1 中,并在虚函数 runFunctor 中被调用。到此我们知道了在线程中执行的函数最终调用的地方是runFunctor()。继续看StoredFunctorCall1 的父类 RunFunctionTask的代码 :

template <typename T>
class RunFunctionTask : public RunFunctionTaskBase<T>
{
public:
    void run() override
    {
        if (this->isCanceled()) {
            this->reportFinished();
            return;
        }
#ifndef QT_NO_EXCEPTIONS
        try {
#endif
            this->runFunctor();// 在此处调用runFunctor函数
#ifndef QT_NO_EXCEPTIONS
        } catch (QException &e) {
            QFutureInterface<T>::reportException(e);
        } catch (...) {
            QFutureInterface<T>::reportException(QUnhandledException());
        }
#endif

        this->reportResult(result);
        this->reportFinished();
    }
    T result;
};

看到RunFunctionTask类成员有个run函数,且runFunctor 函数是在run函数中调通的,说明 run 函数可能是在线程中执行的,Qt中有两个类的run函数是在线程中执行的,一个是QThread子类的run函数,一个是QRunnable子类的run函数。接下来我们看下RunFunctionTask的父类RunFunctionTaskBase 的实现。

template <typename T>
class RunFunctionTaskBase : public QFutureInterface<T> , public QRunnable
{
public:
    QFuture<T> start()
    {
        return start(QThreadPool::globalInstance());
    }

    QFuture<T> start(QThreadPool *pool)
    {
        this->setThreadPool(pool);
        this->setRunnable(this);
        this->reportStarted();
        QFuture<T> theFuture = this->future();
        pool->start(this, /*m_priority*/ 0);
        return theFuture;
    }

    void run() override {}
    virtual void runFunctor() = 0;
};

从上面的代码可以看到RunFunctionTaskBase 继承自QRunnable,且run函数最终是通过线程池调用的。通过这样层层封装大大减少了在线程中执行函数要写的代码,使得多线程编程变得更容易,也避免了在主线程中执行耗时的操作导致的界面卡顿问题。读到这里相信你对QtConcurrentRun的实现原理已经有了一个比较清楚的认识,为应用它来提高程序性能奠定了基础。

2 应用

在明白了QtConcurrentRun 原理之后,我们再来看看什么场景适合使用。下面列举了一些适合使用QtConcurrentRun的情况。

  • 1、 后台计算:当需要进行复杂的计算或处理大量数据时,可以使用QtConcurrentRun在后台线程中执行这些计算,以避免阻塞主线程和保持界面的响应性。

  • 2、文件操作:读取或写入大型文件可能会导致阻塞主线程,使用QtConcurrentRun可以将文件操作放在后台线程中进行,以确保主线程的流畅运行。

  • 3、 网络请求:执行网络请求时,如果需要等待服务器响应或下载大量数据,使用QtConcurrentRun可以将网络请求放在后台线程中,以免阻塞主线程和提高应用程序的性能。

  • 4、并行任务:对于可以并行执行的任务,例如批量处理图像或处理多个数据源,可以使用QtConcurrentRun在多个线程中同时执行任务,以提高执行效率。

3 示例

使用QtConcurrentRun非常简单。以下是一个简单的示例代码,展示了如何使用QtConcurrentRun在后台线程中执行一个函数:

#include 
#include 

void myFunction(int value)
{
    qDebug() << "Running in background thread. Value:" << value;
    // 执行耗时操作
}

int main()
{
    int value = 42;

    // 在后台线程中执行myFunction
    QtConcurrent::run(myFunction, value);

    // 继续执行主线程的其他操作
    // ...

    return 0;
}

上述示例中,myFunction函数会在后台线程中执行,并打印出传入的value值。主线程可以继续执行其他操作,而不会被myFunction的执行所阻塞。

4 总结

总结而言,QtConcurrentRun提供了一种方便的方式来在后台线程中执行函数或Lambda表达式,使得开发人员可以轻松地处理耗时操作,提高应用程序的性能和响应性。它是Qt并发编程的重要工具之一,为开发跨平台应用程序提供了便利和灵活性。以上就是本文的所有内容了,欢迎留言评论指出文中的不足之处,也欢迎留言讨论关于QtConcurrentRun的更丰富的用法。

你可能感兴趣的:(C++,qt,多线程,qtconcurrentrun,c++)