Playing with coroutines and Qt
你好!
我最近想知道C ++中的协程的状态,我发现了几个实现。我决定选择一个用于我的实验。
它简单易用,适用于Linux和Windows。
我的目标是试图找到一种方法来让代码异步运行,而不必等待信号触发插槽,并避免调用QCoreApplication :: processEvents或在堆栈中创建QEventLoop。
我的第一种方法是将自定义事件调度程序的processEvent函数转换为协程并使用yield。几次失败后,我决定不继续这种方式。
我的下一个尝试是将一个插槽转换为协程:
|
1
|
QTimer::singleShot(0, std::bind(&coroutine::resume, coroutine::create([]() { ... }); |
在这个lambda中,CPU将执行代码直到yield,它将跳回到应用程序事件循环。
完整的代码是:
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include "coroutine.h"#include <QtCore>#include <QtWidgets>int main(int argc, char **argv){ QApplication app(argc, argv); QPushButton fibonacciButton("0: 0"); fibonacciButton.show(); QObject::connect(&fibonacciButton, &QPushButton::pressed, std::bind(&coroutine::resume, coroutine::create([&]() { qulonglong f0 = 1, f1 = 0, n = 1; fibonacciButton.setText(QString("1: 1")); coroutine::yield(); fibonacciButton.setText(QString("2: 1")); forever { auto next = f1 + f0; f0 = f1; f1 = next; fibonacciButton.setText(QString("%0: %1").arg(n++).arg(f0 + f1)); coroutine::yield(); } }))); return app.exec();} |
在这里我们可以看到一个连接到一个lambda函数的按钮,它可以计算斐波那契数列中的数字。在计算下一个数字之后,我们调用yield,它将从该函数跳转到事件循环。当用户再次按下该按钮时,代码将在收益率之后返回到下一行。
这个例子的作用是因为用户需要再次按下按钮来恢复代码的执行。
但是,有时我们想要自动恢复执行。为此,我们需要产生执行并安排执行的简历:
|
1
2
3
4
五
6
|
void qYield(){ const auto routine = coroutine::current(); QTimer::singleShot(0, std::bind(&coroutine::resume, routine)); coroutine::yield();} |
第一行获取协程的标识符,第二行安排恢复。有了yield,CPU会回到以前的帧,最后到达主循环,并且无条件恢复代码。
下一步是在情况发生时尝试恢复。Qt提供了指示什么时候发生的信号,所以更优化的执行方式是:
|
1
2
3
4
五
6
7
8
9
|
template <typename Func>void qAwait(const typename QtPrivate::FunctionPointer::Object *sender, Func signal){ const auto routine = coroutine::current(); const auto connection = QObject::connect(sender, signal, std::bind(&coroutine::resume, routine)); coroutine::yield(); QObject::disconnect(connection);} |
我们创建一个临时连接来恢复插槽的执行,而不是排队恢复。
一个例子可以是:
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include "coroutine.h"#include <QtCore>#include <QtWidgets>#include <QtNetwork>int main(int argc, char **argv){ QApplication app(argc, argv); QPlainTextEdit textEdit; textEdit.show(); QTimer::singleShot(0, std::bind(&coroutine::resume, coroutine::create([&]() { QUrl url("http://download.qt.io/online/qt5/linux/x64/online_repository/Updates.xml"); QNetworkRequest request(url); QNetworkAccessManager manager; auto reply = manager.get(request); qAwait(reply, &QNetworkReply::finished); textEdit.setPlainText(reply->readAll()); reply->deleteLater(); }))); return app.exec();} |
在这里,我创建了一个QTextEdit,它从互联网上接收文件的内容。当QNetworkReply完成时,数据被写入QTextEdit。
另一个例子:
|
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#include "coroutine.h"#include <QtCore>#include <QtWidgets>#include <QtNetwork>int main(int argc, char **argv){ QApplication app(argc, argv); QPlainTextEdit edit; edit.show(); QTimer::singleShot(0, std::bind(&coroutine::resume, coroutine::create([&]() { auto previousText = edit.toPlainText(); forever { if (edit.toPlainText() == QStringLiteral("quit")) { qApp->quit(); } else if (previousText != edit.toPlainText()) { qDebug() << previousText << "->" << edit.toPlainText(); previousText = edit.toPlainText(); } qAwait(&edit, &QPlainTextEdit::textChanged); qDebug() << "QPlainTextEdit::textChanged"; } }))); return app.exec();} |
每次用户修改文本时,该应用程序都会打印文本,并在用户写入“退出”字时完成执行。
https://blog.qt.io/blog/2018/05/29/playing-coroutines-qt/
Playing with coroutines and Qt的更多相关文章
- Qt: The State Machine Framework 学习
State Machine,即为状态机,是Qt中一项非常好的框架.State Machine包括State以及State间的Transition,构成状态和状态转移.通过状态机,我们可以很方便地实现很 ...
- qt Multimedia 模块类如何使用?
qt 多媒体模块介绍 类名 英文描述 中文描述 QAudioBuffer Represents a collection of audio samples with a specific format ...
- Qt Multimedia 模块类如何使用?(表格)
qt 多媒体模块介绍 类名 英文描述 中文描述 QAudioBuffer Represents a collection of audio samples with a specific format ...
- API Design Principles -- QT Project
[the original link] One of Qt’s most reputed merits is its consistent, easy-to-learn, powerfulAPI. T ...
- qtchooser - a wrapper used to select between Qt development binary(2种方法)
---------------------------------------------------------------------------------------------------- ...
- GStreamer基础教程11 - 与QT集成
摘要 通常我们的播放引擎需要和GUI进行集成,在使用GStreamer时,GStreamre会负责媒体的播放及控制,GUI会负责处理用户的交互操作以及创建显示的窗口.本例中我们将结合QT介绍如何指定G ...
- 简单的多屏播放器示例(vlc+qt)
介绍 简单的多屏播放器 最多同时播放16个视频 支持本地文件和rtsp.rtmp等流媒体播放 VS2015工程,依赖Qt+VLC 练手作品 截图 下载 程序:download.csdn.net/d ...
- vlc音视频开发(一)环境搭建(qt篇)
来源:微信公众号「编程学习基地」 目录 简介 qt配置vlc环境 simple_libvlc_qt_player 项目地址 简介 VLC 是一款自由.开源的跨平台多媒体播放器及框架,可播放大多数多媒体 ...
- QT内省机制、自定义Model、数据库
本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源: 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex) ...
随机推荐
- Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.3
3.Spark MLlib Deep Learning Convolution Neural Network(深度学习-卷积神经网络)3.3 http://blog.csdn.net/sunbow0 ...
- osgi实战学习之路:1. ant+bnd+felix搭建osgi之HelloWorld
开发环境分为三个部份 osgi_provider: bundle开发环境,对外提供服务 osgi_consumer: 引用其他bundle osgi_main: 执行測试 项目主要内容 : commo ...
- RTP 和 RTSP的区别
RTP(Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传输协议.RTP被定义为在一对一或一对多的传输情况下工作.其目的是提供时间信息和实现流同 ...
- Kinect 开发 —— 骨骼追踪进阶(上)
Kinect传感器核心只是发射红外线,并探测红外光反射,从而可以计算出视场范围内每一个像素的深度值.从深度数据中最先提取出来的是物体主体和形状,以及每一个像素点的游戏者索引信息.然后用这些形状信息来匹 ...
- C# WPF开源控件库MaterialDesign介绍
介绍 1.由于前端时间萌发开发一个基础架构得WPF框架得想法, 然后考虑到一些界面层元素统一, 然后就无意间在GitHub上发现一个开源WPF UI, 于是下载下来了感觉不错. 官网地址:http:/ ...
- 深入研究java.lang.ThreadLocal类 (转)
深入研究java.lang.ThreadLocal类 一.概述 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thr ...
- ArcGIS Api For Flex 动态画点和线
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...
- jmeter响应数据中文乱码问题
进入jmeter安装文件目录:D:\Program File\apache-jmeter-2.13\apache-jmeter-2.13\bin\ 修改jmeter.properties文件,在最下方 ...
- goinstall
[背景] 折腾: [记录]go语言中通过log4go实现同时输出log信息到log文件和console 期间,以: http://code.google.com/p/log4go/ 为例,如何安装第三 ...
- 2018-8-10 模拟赛T3(可持久化线段树)
出题人说:正解离线按DFS序排序线段维护区间和 但是对于树上每个点都有一个区间和一个值,两个点之间求1~m的区间和,这不就是用可持久化线段树吗. 只不过这个线段树需要区间修改,不过不需要标记下传,询问 ...