QT异步作用序列
Qt asynchronous action sequence
在C /QT程序中,我需要按照"完成"信号(例如网络下载,QProcess
等)运行一些异步任务,在最后一个结束后每个任务。
我唯一能想到的方法是为每个步骤拥有一个单独的状态类(例如,冗长,例如同步程序中的每行单独的类别),或者拥有一个带有状态枚举和字段的大型类保留不同步骤所需的所有可能对象(不灵活,难以维护)。有什么好的解决方案吗?似乎这应该是一个常见的问题,但是我找不到任何东西。
命令模式
我唯一能想到的方法是为每个步骤(极端冗长)拥有一个单独的状态类
实际上,这种方法没有错。它称为命令模式,为每个动作创建一个单独的类。
您可以使用QRunnable
和QQueue
实现它。
-
QRunnable
是一个可运行的对象。您从中继承了类并重新完成run()
方法,该方法将执行单个异步工作(例如,下载文件)。 -
QQueue
是一个简单的容器,它实现了"首先,首先出局"(FIFO)。您可以使用任何适合您需求的容器-QList
,QStack
等
一般实施
在可运行的对象中创建一个done()
信号,并在其run()
方法的末尾发射它。要查询新任务,只需将新的QRunnable
对象推到容器中,然后将done()
信号连接到某个插槽,该插槽将dequeue
并运行一个任务。
如果基础类(与QProcess
,QNetworkManager
等不同)不是通过设计异步,则可以使用QtConcurrent::run()
来实现异步运行。
另请参见
您也可以将QRunnable
与QThreadPool
一起使用,并手动设置并发任务的限制。在这里,您可以阅读有关QT多线程技术的更多信息。
有很多方法。一种基本模式是将函子连接到done()
信号:
struct Task : QObject {
Q_SLOT void start() {}
Q_SIGNAL void done();
Q_OBJECT
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
using Q = QObject;
Task task1, task2, task3;
Q::connect(&task1, &Task::done, &task2, [&]{ task2.start(); });
Q::connect(&task2, &Task::done, &task3, [&]{ task3.start(); });
Q::connect(&task3, &Task::done, &app, [&]{ app.quit(); });
return app.exec();
}
我们可以考虑有关特定类的done
信号的知识:
template <typename F> void onDone(QProcess * process, QObject * dst, F && f) {
using signal_type = void(QProcess::*)(int,QProcess::ExitStatus);
QObject::connect(process, static_cast<signal_type>(&QProcess::finished),
dst, std::forward<F>(f));
}
template <typename F> void onDone(QNetworkReply * reply, QObject * dst, F && f) {
QObject::connect(reply, &QNetworkReply::finished, dst, std::forward<F>(f));
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QNetworkAccessManager mgr;
auto download = mgr.get(QNetworkRequest{QUrl{"http://www.google.com"}});
QProcess process;
onDone(download, &process, [&]{ process.start(); });
onDone(&process, &app, [&]{ app.quit(); });
return app.exec();
}
如果在班级或一对中有特定的行为,则可以将它们分解出来。特质类别有助于防止由于多个可能的配对而导致的组合爆炸:
// https://github.com/KubaO/stackoverflown/tree/master/questions/task-sequence-37903585
#include <QtCore>
#include <QtNetwork>
#include <type_traits>
template <typename T> struct SourceAction;
template<> struct SourceAction<QProcess> {
using signal_type = void(QProcess::*)(int,QProcess::ExitStatus);
static constexpr signal_type source(QProcess*) {
return static_cast<signal_type>(&QProcess::finished); }
};
template<> struct SourceAction<QNetworkReply> {
using signal_type = void(QNetworkReply::*)();
static constexpr signal_type source(QNetworkReply*) { return &QNetworkReply::finished; }
};
template <typename T> struct TargetAction;
template<> struct TargetAction<QProcess> {
struct slot_type {
QProcess * process;
void operator()() { process->start(); }
slot_type(QProcess* process) : process(process) {}
};
static slot_type destination(QProcess * process) { return slot_type(process); }
};
template<> struct TargetAction<QCoreApplication> {
using slot_type = void(*)();
static constexpr slot_type destination(QCoreApplication*) { return &QCoreApplication::quit; }
};
// SFINAE
template <typename Src, typename Dst>
void proceed(Src * src, Dst * dst) {
QObject::connect(src, SourceAction<Src>::source(src),
dst, TargetAction<Dst>::destination(dst));
}
template <typename Src, typename F>
void proceed(Src * src, F && f) {
QObject::connect(src, SourceAction<Src>::source(src), std::forward<F>(f));
}
QNetworkReply * download(QNetworkAccessManager * mgr, const QUrl & url) {
return mgr->get(QNetworkRequest{url});
}
QProcess * setup(QProcess * process, const QString & program, const QStringList & args) {
process->setProgram(program);
process->setArguments(args);
return process;
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
if (app.arguments().count() > 1) return 0;
QNetworkAccessManager mgr;
QProcess process;
proceed(download(&mgr, {"http://www.google.com"}), &process);
proceed(setup(&process, app.applicationFilePath(), {"dummy"}), &app);
proceed(&process, []{ qDebug() << "quitting"; });
return app.exec();
}
您还可以以类似的声明方式利用状态机系统。
相关文章:
- 我的神经网络不起作用 [XOR 问题]
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 未在作用域中声明unordered_map
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么在保护模式下继承升级不起作用
- 循环在计数器中不起作用
- 有没有一种方法可以在编译时获得作用域类名
- 在其他文件中创建类时在 c++ 项目中不起作用
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 为什么二进制搜索在我的测试中不起作用
- C++quit()函数中可能存在作用域问题
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 带有指定长度字符* 参数的 std::regex_search 在 VS2017 中不起作用?
- QT异步作用序列
- 提升异步操作不起作用(对我来说)
- 提升ASIO.当我的程序继续发送数据时,异步接收不起作用
- c++boost asio异步函数在dll中不起作用