当前位置: 首页 > news >正文

QtConcurrent::run并发

QtConcurrent::run:(在另一个线程中运行一个函数。)

相当于:

QtConcurrent::run(QThreadPool::globalInstance(), function, ...);

在单独的线程中运行function 。线程取自全局QThreadPool 。请注意,function 可能不会立即运行;function 只有在线程可用时才会运行。

在基本模式下,T 与function 的返回值类型相同。非虚返回值可通过QFuture::result() 函数访问。

在基本模式下,返回的QFuture 只能用于查询函数的运行/完成状态和返回值。特别是,只有在未来的计算尚未开始时,才能取消或暂停。

在带承诺运行模式下,function 将返回 void,并且必须接受一个QPromise<T> & 类型的额外参数,作为第一个参数放在函数参数列表中。T 是结果类型,与返回的QFuture<T> 相同。

在带承诺运行模式下,与基本模式类似,返回的QFuture 可用于查询函数的运行/完成状态和报告值。此外,它还可用于暂停或取消正在运行的任务,从被调用的function 获取多个结果,或监控function 报告的进度。

QtConcurrent::run() 函数在单独的线程中运行一个函数。函数的返回值通过QFuture API 提供。

QtConcurrent::run() 是一个重载方法。您可以将这些重载视为略有不同的模式。在基本模式下,传递给 QtConcurrent::run() 的函数只能向调用者报告一个计算结果。在 "带承诺运行 "模式下,传递给 QtConcurrent::run() 的函数可以使用附加的QPromise API,该 API 可实现多重结果报告、进度报告、在调用者要求时暂停计算或在调用者要求时停止计算。

该函数是Qt Concurrent 框架的一部分。Concurrent Run | Qt Concurrent 6.8.2

并发运行(基本模式)

传递给 QtConcurrent::run() 的函数可通过其返回值报告结果。

在独立线程中运行函数

要在另一个线程中运行函数,请使用 QtConcurrent::run():

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);

这将在从默认QThreadPool 获取的独立线程中运行aFunction 。您可以使用QFuture 和QFutureWatcher 类监控函数的状态。

要使用专用线程池,可以将QThreadPool 作为第一个参数:

extern void aFunction();
QThreadPool pool;
QFuture<void> future = QtConcurrent::run(&pool, aFunction);

向函数传递参数

向函数传递参数的方法是将参数添加到 QtConcurrent::run() 调用中,紧跟在函数名称之后。例如

extern void aFunctionWithArguments(int arg1, double arg2, const QString &string);

int integer = ...;
double floatingPoint = ...;
QString string = ...;

QFuture<void> future = QtConcurrent::run(aFunctionWithArguments, integer, floatingPoint, string);

在调用 QtConcurrent::run() 时,会复制每个参数,这些值会在线程开始执行函数时传递给线程。调用 QtConcurrent::run() 后对参数所做的更改线程是看不到的。

请注意,QtConcurrent::run 不支持直接调用重载函数。例如,下面的代码将无法编译:

void foo(int arg);
void foo(int arg1, int arg2);
...
QFuture<void> future = QtConcurrent::run(foo, 42);

最简单的解决方法是通过 lambda 调用重载函数:

QFuture<void> future = QtConcurrent::run([] { foo(42); });

或者使用static_cast 告诉编译器选择哪个重载函数:

QFuture<void> future = QtConcurrent::run(static_cast<void(*)(int)>(foo), 42);

或qOverload :

QFuture<void> future = QtConcurrent::run(qOverload<int>(foo), 42);

从函数返回值

函数的任何返回值都可以通过QFuture 获取:

extern QString functionReturningAString();
QFuture<QString> future = QtConcurrent::run(functionReturningAString);
...
QString result = future.result();

如果不需要结果(例如,因为函数返回void ),使用QThreadPool::start() 重载获取函数对象会更有效。

如上文所述,传递参数是这样进行的:

extern QString someFunction(const QByteArray &input);

QByteArray bytearray = ...;

QFuture<QString> future = QtConcurrent::run(someFunction, bytearray);
...
QString result = future.result();

请注意,QFuture::result() 函数会阻塞并等待结果可用。当函数执行完毕、结果可用时,请使用QFutureWatcher 获取通知。

其他应用程序接口功能

使用成员函数

QtConcurrent::run() 也接受指向成员函数的指针。第一个参数必须是常量引用或指向类实例的指针。通过常量引用传递有助于调用常量成员函数;通过指针传递有助于调用修改实例的非常量成员函数。

例如,在一个单独的线程中调用QByteArray::split() (一个常量成员函数)是这样完成的:

// call 'QList<QByteArray>  QByteArray::split(char sep) const' in a separate thread
QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(&QByteArray::split, bytearray, ' ');
...
QList<QByteArray> result = future.result();

调用非 const 成员函数的方法如下

// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread
QImage image = ...;
QFuture<void> future = QtConcurrent::run(&QImage::invertPixels, &image, QImage::InvertRgba);
...
future.waitForFinished();
// At this point, the pixels in 'image' have been inverted
使用 Lambda 函数

调用 lambda 函数的方法如下

QFuture<void> future = QtConcurrent::run([=]() {
    // Code in this block will run in another thread
});
...

调用函数修改通过引用传递的对象的过程如下:

static void addOne(int &n) { ++n; }
...
int n = 42;
QtConcurrent::run(&addOne, std::ref(n)).waitForFinished(); // n == 43

使用可调用对象的方法如下

struct TestClass
{
    void operator()(int s1) { s = s1; }
    int s = 42;
};

...

TestClass o;

// Modify original object
QtConcurrent::run(std::ref(o), 15).waitForFinished(); // o.s == 15

// Modify a copy of the original object
QtConcurrent::run(o, 42).waitForFinished(); // o.s == 15

// Use a temporary object
QtConcurrent::run(TestClass(), 42).waitForFinished();

// Ill-formed
QtConcurrent::run(&o, 42).waitForFinished(); // compilation error

使用承诺并发运行

与 QtConcurrent::run() 的基本模式相比,Run With Promise模式可对运行任务进行更多控制。它允许报告运行任务的进度、报告多个结果、根据请求暂停执行或根据调用者的要求取消任务。

强制 QPromise 参数

Run With Promise带承诺运行)模式下,传递给 QtConcurrent::run() 的函数应该有一个QPromise<T> & 类型的附加参数,其中T 是计算结果的类型(它应该与 QtConcurrent::run() 返回的QFuture<T> 的类型T 相匹配),例如:

extern void aFunction(QPromise<void> &promise);
QFuture<void> future = QtConcurrent::run(aFunction);

promise 参数在 QtConcurrent::run() 函数中被实例化,其引用被传递给调用的aFunction ,因此用户在此模式下调用 QtConcurrent::run() 时无需实例化它,也无需明确传递它。

QPromise 类型的附加参数始终需要作为第一个参数出现在函数的参数列表中,例如

extern void aFunction(QPromise<void> &promise, int arg1, const QString &arg2);

int integer = ...;
QString string = ...;

QFuture<void> future = QtConcurrent::run(aFunction, integer, string);

报告结果

与 QtConcurrent::run() 的基本模式不同,在Run With Promise模式下传递给 QtConcurrent::run() 的函数总是返回 void 类型。结果报告通过QPromise 类型的附加参数完成。它还支持多重结果报告,例如:

void helloWorldFunction(QPromise<QString> &promise)
{
    promise.addResult("Hello");
    promise.addResult("world");
}

QFuture<QString> future = QtConcurrent::run(helloWorldFunction);
...
QList<QString> results = future.results();

注意: 无需调用QPromise::start() 和QPromise::finish() 来指示计算的开始和结束(通常使用QPromise 时会这样做)。QtConcurrent::run() 总是会在开始和结束执行之前调用它们。

暂停和取消执行

如果需要,QPromise API 还可以暂停和取消计算:

void aFunction(QPromise<int> &promise)
{
    for (int i = 0; i < 100; ++i) {
        promise.suspendIfRequested();
        if (promise.isCanceled())
            return;

        // computes the next result, may be time consuming like 1 second
        const int res = ... ;
        promise.addResult(res);
    }
}

QFuture<int> future = QtConcurrent::run(aFunction);

... // user pressed a pause button after 10 seconds
future.suspend();

... // user pressed a resume button after 10 seconds
future.resume();

... // user pressed a cancel button after 10 seconds
future.cancel();

调用future.suspend() 时,运行中的任务会请求暂停执行。调用该方法后,运行任务将在其迭代循环中下一次调用promise.suspendIfRequested() 后暂停。在这种情况下,运行中的任务将阻塞对promise.suspendIfRequested() 的调用。被阻塞的调用将在调用future.resume() 后解除阻塞。请注意,suspendIfRequested() 内部使用等待条件来解除阻塞,因此运行中的线程会进入空闲状态,而不是在阻塞时浪费资源,以便定期检查恢复请求是否来自调用者的线程。

最后一行对future.cancel() 的调用导致下一次对promise.isCanceled() 的调用将返回true ,而aFunction 将立即返回,不再报告任何结果。

注意: 取消后无需调用QPromise::finish() 来停止计算(通常使用QPromise 时会这样做)。QtConcurrent::run() 总是会在执行结束后调用它。

进度报告

也可以独立于结果报告来报告任务的进度,例如

void aFunction(QPromise<int> &promise)
{
    promise.setProgressRange(0, 100);
    int result = 0;
    for (int i = 0; i < 100; ++i) {
        // computes some part of the task
        const int part = ... ;
        result += part;
        promise.setProgressValue(i);
    }
    promise.addResult(result);
}

QFutureWatcher<int> watcher;
QObject::connect(&watcher, &QFutureWatcher::progressValueChanged, [](int progress){
    ... ; // update GUI with a progress
    qDebug() << "current progress:" << progress;
});
// 连接信号以便知道异步任务何时完成
QObject::connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher](void) {
		// 异步任务完成时的回调
		auto info = watcher->result();
		//todo
		delete watcher;
	});
watcher.setFuture(QtConcurrent::run(aFunction));

调用者为 QtConcurrent::run() 返回的QFuture 安装QFutureWatcher ,以便连接到progressValueChanged() 信号,并相应地更新图形用户界面等。

使用重载操作符()()调用函数

默认情况下,QtConcurrent::run() 在"带承诺运行"模式下不支持带有重载操作符()()的函数。在重载函数的情况下,用户需要明确指定结果类型作为模板参数传递给 QtConcurrent::run(),例如

struct Functor {
    void operator()(QPromise<int> &) { }
    void operator()(QPromise<double> &) { }
};

Functor f;
run<double>(f); // this will select the 2nd overload
// run(f);      // error, both candidate overloads potentially match

QtConcurrent Namespace | Qt Concurrent 6.8.2

Concurrent Run | Qt Concurrent 6.8.2

相关文章:

  • 如何选择免费中文 Postman 替代工具?
  • 高度电路中时序设计之二
  • CentOS 7部署主域名服务器 DNS
  • 动态规划之完全背包
  • 《TypeScript 面试八股:高频考点与核心知识点详解》
  • 若依框架二次开发——若依集成 JSEncrypt 实现密码加密传输方式
  • 【重装系统】全流程记录,在 MacOS 的电脑上烧录 Ubuntu 启动盘
  • 2025年渗透测试面试题总结-某shopee -红队-Singapore(题目+回答)
  • 练习题:103
  • 【LeetCode 热题100】 4. 寻找两个正序数组的中位数的算法思路及python代码
  • 数据库的视图有什么用?
  • SSRF服务器请求伪造攻击
  • AI+Xmind自动生成测试用例(思维导图格式)
  • 小程序内表格合并功能实现—行合并
  • C 语言中, scanf 函数在哪些情况下会结束输入读取:
  • C# .net ai Agent AI视觉应用 写代码 改作业 识别屏幕 标注等
  • 批量处理word里面表格的空白行
  • 模型 杜根定律
  • fuse性能选项meta_cache_mode
  • C++ 多线程简要讲解
  • 东莞建网站公司/目前最流行的拓客方法
  • 怎么编网站/阿里巴巴国际贸易网站
  • wordpress简约商城/苏州整站优化
  • wordpress留言板页面/长春关键词优化报价
  • html怎么做静态网站/学seo网络推广
  • 设计一个个人网站的具体步骤/网站推广优化网址