你好!
我最近想知道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的更多相关文章

  1. Qt: The State Machine Framework 学习

    State Machine,即为状态机,是Qt中一项非常好的框架.State Machine包括State以及State间的Transition,构成状态和状态转移.通过状态机,我们可以很方便地实现很 ...

  2. qt Multimedia 模块类如何使用?

    qt 多媒体模块介绍 类名 英文描述 中文描述 QAudioBuffer Represents a collection of audio samples with a specific format ...

  3. Qt Multimedia 模块类如何使用?(表格)

    qt 多媒体模块介绍 类名 英文描述 中文描述 QAudioBuffer Represents a collection of audio samples with a specific format ...

  4. API Design Principles -- QT Project

    [the original link] One of Qt’s most reputed merits is its consistent, easy-to-learn, powerfulAPI. T ...

  5. qtchooser - a wrapper used to select between Qt development binary(2种方法)

    ---------------------------------------------------------------------------------------------------- ...

  6. GStreamer基础教程11 - 与QT集成

    摘要 通常我们的播放引擎需要和GUI进行集成,在使用GStreamer时,GStreamre会负责媒体的播放及控制,GUI会负责处理用户的交互操作以及创建显示的窗口.本例中我们将结合QT介绍如何指定G ...

  7. 简单的多屏播放器示例(vlc+qt)

      介绍 简单的多屏播放器 最多同时播放16个视频 支持本地文件和rtsp.rtmp等流媒体播放 VS2015工程,依赖Qt+VLC 练手作品 截图 下载 程序:download.csdn.net/d ...

  8. vlc音视频开发(一)环境搭建(qt篇)

    来源:微信公众号「编程学习基地」 目录 简介 qt配置vlc环境 simple_libvlc_qt_player 项目地址 简介 VLC 是一款自由.开源的跨平台多媒体播放器及框架,可播放大多数多媒体 ...

  9. QT内省机制、自定义Model、数据库

    本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源: 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex) ...

随机推荐

  1. jquery--延迟对象

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  2. es6 --- Generator 函数

    第一部分,ES6 中的 Generator 在 ES6 出现之前,基本都是各式各样类似Promise的解决方案来处理异步操作的代码逻辑,但是 ES6 的Generator却给异步操作又提供了新的思路, ...

  3. 56.lambda表达式与绑定以及伪函数和绑定

    #include <iostream> #include <functional> using namespace std; using namespace std::plac ...

  4. python2 pip安装包等出现各种编码错误UnicodeDecodeError: 'ascii'(/或者utf-8) codec can't decode byte 0xd2...

    1.问题描述: python2环境,pip安装包时报错UnicodeDecodeError: 'ascii'(/或者utf-8) codec can't decode byte 0xd2... 类似如 ...

  5. Ubuntu下SVN服务器安装和配置

    一.SVN安装1.安装包$ sudo apt-get install subversion 2.添加svn管理用户及subversion组#添加用户$ sudo adduser  svnuser#添加 ...

  6. 如何优雅的写UI——(6)内存泄漏

    控件讲了这么久,其实我的程序有两个Bug不知道大家有没有发现,这两个Bug都不会报错,对程序运行来说都没有阻碍,但是这种Bug对整个代码来说是一个很大的安全隐患. 什么是内存泄漏 内存泄漏(Memor ...

  7. Java第三方工具库/包汇总

    一.科学计算或矩阵运算库 科学计算包: JMathLib是一个用于计算复杂数学表达式并能够图形化显示计算结果的Java开源类库.它是Matlab.Octave.FreeMat.Scilab的一个克隆, ...

  8. HDU 1166 敌兵布阵 Segment Tree题解

    本题是最主要的分段树操作了.或者一般叫线段树,只是好像和线段没什么关系,仅仅是分段了. 不使用lazy标志,更新仅仅是更新单点. 假设不使用分段树,那么更新时间效率仅仅须要O(1),使用分段树更新效率 ...

  9. IAR for STM8介绍、下载、安装与注册--转

    Ⅰ.写在前面 本文讲述的内容是IAR for STM8的介绍.下载.安装与注册,其安装.注册过程和IAR for ARM类似,如果需要了解IAR for ARM相关的文章,可以到我博客,或微信公众号查 ...

  10. 关于img标签的探讨

    关于img标签的探讨:一直以来img属于那一种标签受到困惑,因为它既有块元素的特性也有行内元素的属性.它独占一行,也可以设置宽高. 在此重新学习一下标签元素的分类;html元素的分类:块元素.内联元素 ...