TaskTree 类
class Tasking::TaskTreeThe TaskTree class runs an async task tree structure defined in a declarative way. More...
头文件 | #include <solutions/tasking/tasktree.h> |
继承 | QObject |
注意:此类的所有函数都是可重入的。
公共函数
TaskTree() | |
TaskTree(const Tasking::Group &recipe) | |
虚拟的 | ~TaskTree() |
int | asyncCount() const |
void | cancel() |
bool | isRunning() const |
void | onStorageDone(const Tasking::Storage<StorageStruct> &storage, Handler &&handler) |
void | onStorageSetup(const Tasking::Storage<StorageStruct> &storage, Handler &&handler) |
int | progressMaximum() const |
int | progressValue() const |
Tasking::DoneWith | runBlocking() |
Tasking::DoneWith | runBlocking(const QFuture<void> &future) |
void | setRecipe(const Tasking::Group &recipe) |
void | start() |
int | taskCount() const |
信号
void | asyncCountChanged(int count) |
void | done(Tasking::DoneWith result) |
void | progressValueChanged(int value) |
void | started() |
静态公共成员
Tasking::DoneWith | runBlocking(const Tasking::Group &recipe, std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) |
Tasking::DoneWith | runBlocking(const Tasking::Group &recipe, const QFuture<void> &future, std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) |
详细描述
使用 Tasking 命名空间构建可扩展的声明式任务树结构,其中可能包含异步任务,例如 QProcess、网络查询或 ConcurrentCall
根元素和任务
TaskTree 有一个强制性的 Group 根元素,可以包含任意数量的各种类型任务,例如 QProcessTask、NetworkQueryTask 或 ConcurrentCallTask
using namespace Tasking; const Group root { QProcessTask(...), NetworkQueryTask(...), ConcurrentCallTask<int>(...) }; TaskTree *taskTree = new TaskTree(root); connect(taskTree, &TaskTree::done, ...); // finish handler taskTree->start();
上方的任务树包含顶级组元素,该元素包含类型为QProcessTask、NetworkQueryTask和< ConcurrentCallTask
当最后一个正在运行的任务成功完成后,任务树被认为是成功运行的,并且会发出< a href="tasking-tasktree.html#done" translate="no">done()信号,携带< a href="tasking.html#DoneWith-enum" translate="no">DoneWith::Success。当任务以错误完成时,任务树的执行将停止,剩余的任务将被跳过。任务树以错误结束并发送带有< a href="tasking-tasktree.html#done" translate="no">TaskTree::done()信号的< a href="tasking.html#DoneWith-enum" translate="no">DoneWith::Error。
组
组的父元素将其视为单个任务。与其他任务一样,组可以启动,并且它可以成功完成或以错误结束。可以通过嵌套组元素来创建树状结构。
const Group root { Group { parallel, QProcessTask(...), ConcurrentCallTask<int>(...) }, NetworkQueryTask(...) };
上面的示例与第一个示例的不同之处在于,根元素有一个子组,该子组包含QProcessTask和< ConcurrentCallTask
因此,当启动上面的树时,QProcessTask和< ConcurrentCallTask
因此,根据哪个任务运行更长时间(QProcessTask或< ConcurrentCallTask
情景1 | 情景2 |
---|---|
根组开始 | 根组开始 |
子组开始 | 子组开始 |
QProcessTask开始 | QProcessTask开始 |
< ConcurrentCallTask | < ConcurrentCallTask |
... | ... |
QProcessTask完成 | < ConcurrentCallTask |
... | ... |
< ConcurrentCallTask | QProcessTask完成 |
子组完成 | 子组完成 |
NetworkQueryTask开始 | NetworkQueryTask开始 |
... | ... |
NetworkQueryTask完成 | NetworkQueryTask完成 |
根组完成 | 根组完成 |
特殊情况以粗体标记。省略号表示前一事件(一个或多个任务)和下一事件(一个任务或多个任务)之间的不定时间量(任务或在继续运行)。事件之间没有点意味着它们是同步发生的。
呈现的情景假设所有任务都成功运行。如果任务在执行过程中失败,任务树将以错误结束。特别是,当QProcessTask在< ConcurrentCallTask
任务类型
每个任务类型都与其对应的任务类关联,该类执行任务。例如,任务树内的QProcessTask与执行进程的QProcess类相关联。关联的对象将由任务树在适当的时间自动创建、启动和销毁。
如果一个根组由五个连续的QProcessTask任务组成,并且任务树执行该组,它会为第一个QProcessTask创建一个QProcess实例并启动它。如果QProcess实例成功完成,任务树将其销毁并为第二个QProcessTask创建一个新的QProcess实例,依此类推。如果第一个任务以错误完成,任务树将停止创建QProcess实例,并且根组以错误结束。
以下表格展示了任务类型及其对应的任务类示例
任务类型(受托命名空间) | 相关任务类 | 简要描述 |
---|---|---|
QProcessTask | QProcess | 启动进程。 |
ConcurrentCallTask<ReturnType> | Tasking::ConcurrentCall<ReturnType> | 启动异步任务,在单独的线程中运行。 |
TaskTreeTask | Tasking::TaskTree | 启动嵌套任务树。 |
NetworkQueryTask | NetworkQuery | 启动网络下载。 |
任务处理器
使用任务处理器来设置任务以执行,以及使能在任务以成功或错误完成时读取输出数据。
任务的启动处理器
当创建相应的任务类对象并在其启动之前,任务树调用可选的用户提供的设置处理器。设置处理器应该始终传递相关任务类对象的引用。
const auto onSetup = [](QProcess &process) { process.setCommand({"sleep", {"3"}}); }; const Group root { QProcessTask(onSetup) };
您可以在设置处理器中修改传递的process.start();
,因为任务树在需要时调用它。设置处理器是可选的。当使用时,它必须作为任务的构造函数的第一个参数。
可选地,设置处理器可以返回一个SetupResult。返回的SetupResult会影响特定任务的进一步启动行为。可能的值包括
SetupResult 值 | 简要描述 |
---|---|
继续 | 任务将正常启动。这是当设置处理器没有返回SetupResult(即,其返回类型为空)时的默认行为。 |
成功停止 | 任务不会启动,并将成功报告给父任务。 |
错误停止 | 任务不会启动,并将错误报告给父任务。 |
这在仅在满足条件时运行任务并且需要在之前启动的任务完成之前知道所需评估条件的数据时很有用。这种方式,设置处理器根据需要动态决定是否正常启动相应的任务或跳过它并报告成功或错误。有关任务间数据交换的更多信息,请参阅存储。
任务的完成处理器
当正在运行的任务完成后,任务树调用可选提供的完成处理器。处理器应该接受相关任务类对象的const
引用。
const auto onSetup = [](QProcess &process) { process.setCommand({"sleep", {"3"}}); }; const auto onDone = [](const QProcess &process, DoneWith result) { if (result == DoneWith::Success) qDebug() << "Success" << process.cleanedStdOut(); else qDebug() << "Failure" << process.cleanedStdErr(); }; const Group root { QProcessTask(onSetup, onDone) };
完成处理器可以从
注意:如果任务设置处理器返回StopWithSuccess或StopWithError,则不调用完成处理器。
组处理器
类似于任务处理器,组处理器允许您设置一个组来执行,并在整个组成功完成或发生错误时应用更多操作。
组的开始处理器
任务树在启动子任务之前会调用组开始处理器。组处理器不接收任何参数
const auto onSetup = [] { qDebug() << "Entering the group"; }; const Group root { onGroupSetup(onSetup), QProcessTask(...) };
组设置处理器是可选的。要定义组设置处理器,向组中添加一个onGroupSetup() 元素。onGroupSetup() 的参数是一个用户处理器。如果您向组中添加了多个 onGroupSetup() 元素,则会在运行时触发一个包含错误信息的断言。
与任务的开始处理器一样,组开始处理器可以返回SetupResult。返回的SetupResult值影响整个组的启动行为。如果您未指定组开始处理器或其返回类型为 void,则默认的组操作是SetupResult::Continue,因此所有任务都正常启动。否则,当开始处理器返回SetupResult::StopWithSuccess或SetupResult::StopWithError时,任务不会启动(它们会被跳过),并根据返回的值分别报告组本身的成功或失败。
const Group root { onGroupSetup([] { qDebug() << "Root setup"; }), Group { onGroupSetup([] { qDebug() << "Group 1 setup"; return SetupResult::Continue; }), QProcessTask(...) // Process 1 }, Group { onGroupSetup([] { qDebug() << "Group 2 setup"; return SetupResult::StopWithSuccess; }), QProcessTask(...) // Process 2 }, Group { onGroupSetup([] { qDebug() << "Group 3 setup"; return SetupResult::StopWithError; }), QProcessTask(...) // Process 3 }, QProcessTask(...) // Process 4 };
在上述示例中,一个根组的所有子组都已定义其设置处理器。以下场景假设所有启动的过程都成功完成
场景 | 注释 |
---|---|
根组开始 | 不返回SetupResult,因此其任务会执行。 |
组1开始 | 返回Continue,因此其任务会执行。 |
进程1开始 | |
... | ... |
进程1完成(成功) | |
组1完成(成功) | |
组2开始 | 返回StopWithSuccess,因此进程2被跳过,组2报告成功。 |
组2完成(成功) | |
组3开始 | 返回StopWithError,因此进程3被跳过,组3报告错误。 |
组3完成(错误) | |
根组完成(错误) | 组3,它是根组的直接子代,以错误完成,因此根组停止执行,跳过尚未启动的进程4,并报告错误。 |
组的完成处理器
组的完成处理器在成功或失败执行任务后执行。组报告的最终值取决于其工作流程策略。处理器可以应用其他必要的操作。完成处理器定义在组内的 onGroupDone() 元素中。它可能包含可选的 DoneWith 参数,表示成功或失败执行。
const Group root { onGroupSetup([] { qDebug() << "Root setup"; }), QProcessTask(...), onGroupDone([](DoneWith result) { if (result == DoneWith::Success) qDebug() << "Root finished with success"; else qDebug() << "Root finished with an error"; }) };
组完成处理器是可选的。如果您向组中添加了多个 onGroupDone(),则会在运行时触发一个包含错误信息的断言。
注意:即使组设置处理器返回StopWithSuccess或StopWithError,也会调用组的完成处理器。此行为与任务完成处理器不同,可能会在未来更改。
其他组元素
组可以包含其他描述处理流程的元素,例如执行模式或工作流程策略。它还可以包含负责收集和共享在组执行过程中收集的特定公共数据的存储元素。
执行模式
在组中,执行模式元素指定了组的直接子任务如何启动。最常见的执行模式是顺序和并行。也可以通过使用parallelLimit() 函数来指定并行任务的数量限制。
在所有执行模式下,组按任务出现的顺序启动任务。
如果组的子项也是一个组,则子组根据其自己的执行模式运行其任务。
工作流程策略
组中的工作流程策略元素指定了组如何处理其直接子任务之一完成的情况。有关可能策略的详细描述,请参考WorkflowPolicy。
如果组的子项也是一个组,则子组根据其自己的工作流程策略运行其任务。
存储
使用Storage元素在任务之间交换信息。特别是在顺序执行模式下,在任务需要从其他已完成任务中获取数据之前,任务可以启动。例如,一个通过从源读取并将其写入目标来复制数据的任务树可能如下所示
static QByteArray load(const QString &fileName) { ... } static void save(const QString &fileName, const QByteArray &array) { ... } static Group copyRecipe(const QString &source, const QString &destination) { struct CopyStorage { // [1] custom inter-task struct QByteArray content; // [2] custom inter-task data }; // [3] instance of custom inter-task struct manageable by task tree const Storage<CopyStorage> storage; const auto onLoaderSetup = [source](ConcurrentCall<QByteArray> &async) { async.setConcurrentCallData(&load, source); }; // [4] runtime: task tree activates the instance from [7] before invoking handler const auto onLoaderDone = [storage](const ConcurrentCall<QByteArray> &async) { storage->content = async.result(); // [5] loader stores the result in storage }; // [4] runtime: task tree activates the instance from [7] before invoking handler const auto onSaverSetup = [storage, destination](ConcurrentCall<void> &async) { const QByteArray content = storage->content; // [6] saver takes data from storage async.setConcurrentCallData(&save, destination, content); }; const auto onSaverDone = [](const ConcurrentCall<void> &async) { qDebug() << "Save done successfully"; }; const Group root { // [7] runtime: task tree creates an instance of CopyStorage when root is entered storage, ConcurrentCallTask<QByteArray>(onLoaderSetup, onLoaderDone, CallDoneIf::Success), ConcurrentCallTask<void>(onSaverSetup, onSaverDone, CallDoneIf::Success) }; return root; } const QString source = ...; const QString destination = ...; TaskTree taskTree(copyRecipe(source, destination)); connect(&taskTree, &TaskTree::done, &taskTree, [](DoneWith result) { if (result == DoneWith::Success) qDebug() << "The copying finished successfully."; }); tasktree.start();
在上面的示例中,任务间的数据由一个包含在CopyStorage
自定义结构体中的QByteArray内容变量[2]。如果加载器成功完成,它将数据存储在CopyStorage::content
变量[5]中。然后保存器使用该变量来配置保存任务[6]。
为了使任务树管理CopyStorage
结构体,创建了一个Storage<CopyStorage>
实例[3]。如果将此对象的副本作为组的子项插入[7],则在任务树进入该组时,将动态创建CopyStorage
结构体的实例。当任务树离开此组时,将销毁现有的CopyStorage
结构体实例,因为它不再需要。
如果包含该共同Storage<CopyStorage>
实例副本的多个任务树同时运行(包括当任务树在不同线程中运行时),则每个任务树都包含其自己的CopyStorage
结构体副本。
您可以从组的任何处理程序中通过存储对象访问CopyStorage
。这包括所有具有存储对象的下属任务的处理程序。要访问处理器中的自定义结构体,请将Storage<CopyStorage>
对象的副本传递给处理器(例如,在lambda捕获中)[4]。
当任务树在包含存储的子树中调用处理器时[7],任务树在存储对象内部激活其自己的CopyStorage
实例。因此,只能在处理器体内访问CopyStorage
结构体。要从Storage<CopyStorage>
中访问当前激活的CopyStorage
,请使用Storage::operator->()、Storage::operator*()或Storage::activeStorage()方法。
以下列表总结如何将存储对象用于任务树
- 定义具有自定义数据 [1]、[2] 的自定义结构
MyStorage
- 创建 Storage<
MyStorage>
存储实例 [3] - 将 Storage<
MyStorage>
实例传递给处理器 [4] - 在处理器中访问
MyStorage
实例 [5]、[6] - 将 Storage<
MyStorage>
实例插入组 [7]
TaskTree 类
TaskTree 根据组根元素描述的配方执行异步任务的树结构。
由于 TaskTree 也是异步任务,它可以成为另一个 TaskTree 的一部分。要嵌套 TaskTree 在另一个 TaskTree 中,将 TaskTreeTask 元素插入另一个组元素中。
TaskTree 在运行时报告已完成任务的进度。任务完成或跳过或取消时进度值增加。当 TaskTree 完成,并发射 TaskTree::done() 信号时,当前的进度值等于最大进度值。最大进度等于树中异步任务的总数。嵌套的 TaskTree 计为一个任务,其子任务不计入顶级树。组本身不计入任务,但其任务计入。《a href="tasking-sync.html" translate="no">Sync 任务不是异步任务,因此不计入任务。
为了为运行的树设置其他初始数据,通过安装存储设置处理器在创建树时修改存储实例
Storage<CopyStorage> storage; const Group root = ...; // storage placed inside root's group and inside handlers TaskTree taskTree(root); auto initStorage = [](CopyStorage &storage) { storage.content = "initial content"; }; taskTree.onStorageSetup(storage, initStorage); taskTree.start();
当运行的任务树创建一个 CopyStorage
实例时,在调用树中的任何处理器之前,任务树调用 initStorage 处理器,以设置存储的唯一初始数据,该数据对 taskTree 的此次运行是独有的。
同样,为了收集运行树的某些其他结果数据,在即将销毁它们时从树中的存储实例读取。为此,安装一个存储完成处理器
Storage<CopyStorage> storage; const Group root = ...; // storage placed inside root's group and inside handlers TaskTree taskTree(root); auto collectStorage = [](const CopyStorage &storage) { qDebug() << "final content" << storage.content; }; taskTree.onStorageDone(storage, collectStorage); taskTree.start();
当运行的任务树即将销毁一个 CopyStorage
实例时,任务树调用 collectStorage 处理器,以读取存储的唯一最终数据,该数据对 taskTree 的此次运行是独有的。
任务适配器
要扩展 TaskTree 以包含新的任务类型,实现一个从 TaskAdapter 类模板派生的简单适配器类。以下类是一个单次计时器的适配器,这可以被认为是一个新的异步任务。
class TimerTaskAdapter : public TaskAdapter<QTimer> { public: TimerTaskAdapter() { task()->setSingleShot(true); task()->setInterval(1000); connect(task(), &QTimer::timeout, this, [this] { emit done(DoneResult::Success); }); } private: void start() final { task()->start(); } }; using TimerTask = CustomTask<TimerTaskAdapter>;
您必须从使用实现运行任务的类的模板参数实例化的 TaskAdapter 类模板导出自定义适配器。上面的代码使用 QTimer 来运行任务。这个类之后作为任务处理器的参数出现。此类参数的实例自动成为 TaskAdapter 模板的一个成员,可以通过 TaskAdapter::task() 方法访问。 TimerTaskAdapter
的构造函数最初配置 QTimer 对象并连接到 QTimer::timeout() 信号。当信号被触发时, TimerTaskAdapter
发射 TaskInterface::done(DoneResult::Success) 信号来通知任务树任务已成功完成。如果它发射 TaskInterface::done(DoneResult::Error),则任务以错误完成。 TaskAdapter::start() 方法启动计时器。
为了在TaskTree中的TimerTaskAdapter>
的别名。这样,TimerTask
就变成了一个新的自定义任务类型,并使用
现在,新的任务类型已被注册,您可以在TaskTree中使用它。
const auto onSetup = [](QTimer &task) { task.setInterval(2000); }; const auto onDone = [] { qDebug() << "timer triggered"; }; const Group root { TimerTask(onSetup, onDone) };
当启动包含上述示例根的任务树时,它将在两秒内打印一条调试消息,然后成功完成。
注意:实现运行任务的类应具有默认构造函数,此类的对象应可自由析构。应允许销毁运行中的对象,最好不等待运行任务完成(即,安全的无阻塞析构器运行任务)。为了实现有阻塞析构函数的任务的无阻塞销毁,请考虑使用TaskAdapter的备用Deleter
模板参数。
成员函数文档
TaskTree::TaskTree()
构建一个空的任务树。使用setRecipe()来传递关于任务树如何执行任务以及如何处理完成任务的说明性描述。
启动一个空的任务树是不做任何事的操作,并发出相关警告消息。
TaskTree::TaskTree(const Tasking::Group &recipe)
这是一个重载函数。
使用给定的recipe构建任务树。在任务树启动后,它将执行recipe中包含的任务,并根据传递的描述处理已完成的任务。
[虚拟 noexcept]
TaskTree::~TaskTree()
销毁任务树。
当任务树在销毁时正在运行,它会立即取消所有正在运行的任务。在这种情况下,不调用任何处理器,甚至连组或任务的完成处理器或onStorageDone()处理器都不调用。任务树也不从析构中发出任何信号,甚至不发出done()或progressValueChanged()信号。此行为始终可以信赖。安全地销毁正在运行的任务树是完全安全的。
销毁正在运行的任务树是常见的做法。它确保销毁将快速运行,而无需等待当前正在运行的任务完成,只要使用的任务以其非阻塞方式实现它们的析构函数。
注意:不要从正在运行的任务的处理器或任务树的任何信号中直接调用析构函数。在这些情况下,请使用deleteLater()代替。
另请参阅cancel()。
int TaskTree::asyncCount() const
返回当前异步调用链的实际数量。
返回值表示在任务树运行期间控制返回调用者事件循环的次数。初始化时,此值为0。如果任务树的执行完全同步完成,此值保持为0。如果在调用start()期间成功启动了任何异步任务,则在此调用start()完成之前,此值增加至1。随后,当任意异步任务完成以及任何可能的延续启动时,此值再次增加。这种增加会持续到任务树完成。当任务树发布done()信号时,增加停止。每当此值增加时,都会发布asyncCountChanged()信号。
另请参阅asyncCountChanged()。
[信号]
void TaskTree::asyncCountChanged(int count)
当运行任务树即将返回控制权给调用者的事件循环时,会发出此信号。当任务树开始运行时,此信号会使用$i translate="no">count值为0时发布,随后在每次asyncCount()值增加时发布,并带有更新后的count值。每次发送的信号(除了初始值为0的信号之外)都保证在发出后任务树仍在异步运行。
另请参阅asyncCount()。
void TaskTree::cancel()
取消正在运行的任务树的执行。
立即取消所有正在运行的任务。所有正在运行的任务将以错误结束,调用它们的错误处理程序。所有正在运行的组织将根据其工作流程策略分发处理程序,调用它们的完成处理程序。存储的onStorageDone()处理程序也会被调用。还会发送progressValueChanged()信号。此行为始终可以信赖。
cancel()
函数是同步执行的,因此调用cancel()
之后,所有正在运行的任务已经完成,并且树已经被取消。如果使用的任务以非阻塞方式实现它们的析构函数,则保证cancel()
将快速运行,不会有任何阻塞等待当前正在运行的任务完成。
当任务树为空时,即使用默认构造函数构建的,对cancel()
的调用是no-op,并发出相关警告消息。
否则,当任务树没有开始时,对cancel()
的调用将被忽略。
注意:请勿从任意运行任务的处理器或任务树的信号中直接调用此函数。
另请参阅~TaskTree()。
[信号]
void TaskTree::done(Tasking::DoneWith result)
当任务树完成后,此信号会发布执行的最后结果result。在此信号发布后,任务树不会调用任何处理器或发出任何信号。
注意:请勿在此信号的处理器中直接删除任务树。请使用deleteLater()代替。
另请参阅started()。
bool TaskTree::isRunning() const
如果任务树目前正在运行,则返回true
;否则返回false
。
模板 <typename StorageStruct, typename Handler> void TaskTree::onStorageDone(const Tasking::Storage<StorageStruct> &storage, Handler &&handler)
为存储安装一个完成处理器,以便从运行中的任务树动态检索最终数据。
StorageHandler
将一个对StorageStruct
实例的常量引用。
static QByteArray load(const QString &fileName) { ... } Storage<QByteArray> storage; const auto onLoaderSetup = [](ConcurrentCall<QByteArray> &concurrent) { concurrent.setConcurrentCallData(&load, "foo.txt"); }; const auto onLoaderDone = [storage](const ConcurrentCall<QByteArray> &concurrent) { *storage = concurrent.result(); }; const Group root { storage, ConcurrentCallTask(onLoaderSetup, onLoaderDone, CallDoneIf::Success) }; TaskTree taskTree(root); auto collectStorage = [](const QByteArray &storage){ qDebug() << "final content" << storage; }; taskTree.onStorageDone(storage, collectStorage); taskTree.start();
当运行的任务树即将从一个放置存储的group离开时,它将销毁一个StorageStruct
实例。在与该组中所有可能的处理器调用之后,任务树将调用传递的handler。这允许动态地读取给定存储的最终内容并进一步处理。这允许在任务树之外动态地读取给定存储的最终内容并进一步处理。
运行树取消时也会调用此处理器。但是,在销毁运行树时不调用它。
另请参阅onStorageSetup。
模板 <typename StorageStruct, typename Handler> void TaskTree::onStorageSetup(const Tasking::Storage<StorageStruct> &storage, Handler &&handler)
为存储安装一个设置处理器,以便将初始数据动态地传递给运行中的任务树。
StorageHandler
需要一个对StorageStruct
实例的引用。
static void save(const QString &fileName, const QByteArray &array) { ... } Storage<QByteArray> storage; const auto onSaverSetup = [storage](ConcurrentCall<QByteArray> &concurrent) { concurrent.setConcurrentCallData(&save, "foo.txt", *storage); }; const Group root { storage, ConcurrentCallTask(onSaverSetup) }; TaskTree taskTree(root); auto initStorage = [](QByteArray &storage){ storage = "initial content"; }; taskTree.onStorageSetup(storage, initStorage); taskTree.start();
当运行的任务树进入一个放置存储的group时,它将创建一个StorageStruct
实例,准备好在该组内部使用。在创建StorageStruct
实例后,在调用该组的任何处理器之前,任务树将调用传递的handler。这允许动态设置给定存储的初始内容。稍后,当调用任何组的处理器时,任务树将激活创建并初始化的存储,使其在任意组处理器内可用。
另请参阅onStorageDone。
int TaskTree::progressMaximum() const
返回最大progressValue。
注意:目前,它与taskCount相同。这可能会在将来发生变化。
另请参阅progressValue。
int TaskTree::progressValue() const
返回当前进度值,该值在0
到progressMaximum之间。
返回的数字表示在任务树运行期间已经完成、取消或跳过的任务的数目。当任务树启动时,此数字设置为0
。当任务树完成时,此数字总是等于progressMaximum。
另请参阅progressMaximum()和progressValueChanged。
[信号]
void TaskTree::progressValueChanged(int value)
此信号在运行的任务树完成、取消或跳过某些任务时被发出。该 值 提供了当前完成、取消或跳过的任务总数。当任务树开始,并且发出 started() 信号后,此信号会带有初始的 值 为 0
。当任务树即将完成,并且在发出 done() 信号之前,此信号会带有最终的 值 为 progressMaximum。
另请参阅 progressValue() 和 progressMaximum。
Tasking::DoneWith TaskTree::runBlocking()
执行带有 QEventLoop::ExcludeUserInputEvents 的本地事件循环并启动任务树。
如果任务树成功完成,则返回 DoneWith::Success;否则,返回 DoneWith::Error。
注意: 请勿在主线程中使用此方法。请使用异步的 start()。此方法应在非主线程或自动测试中使用。
另请参阅 start。
Tasking::DoneWith TaskTree::runBlocking(const QFuture<void> &future)
此函数重载了 runBlocking()。
传入的 future 用于监听取消事件。当任务树取消时,此方法将取消传入的 future。
[静态]
Tasking::DoneWith TaskTree::runBlocking(const Tasking::Group &recipe, std::chrono::milliseconds timeout = std::chrono::milliseconds::max())
使用传入的 recipe 构造一个临时任务树并运行它。
可选地提供的 timeout 在经过 timeout 毫秒后自动取消树。
如果任务树成功完成,则返回 DoneWith::Success;否则,返回 DoneWith::Error。
注意: 请勿在主线程中使用此方法。请使用异步的 start()。此方法应在非主线程或自动测试中使用。
另请参阅 start。
[静态]
Tasking::DoneWith TaskTree::runBlocking(const Tasking::Group &recipe, const QFuture<void> &future, std::chrono::milliseconds timeout = std::chrono::milliseconds::max())
此函数重载了 runBlocking(const Group &recipe, milliseconds timeout)。
传入的 future 用于监听取消事件。当任务树取消时,此方法将取消传入的 future。
void TaskTree::setRecipe(const Tasking::Group &recipe)
为任务树设置给定的 recipe。任务树启动后,它执行 recipe 中包含的任务,并根据传入的描述处理完成的任务。
注意: 当对正在运行的任务树调用地时,该方法被忽略。
另请参阅 TaskTree(const Tasking::Group &recipe) 和 start。
void TaskTree::start()
启动任务树。
使用 setRecipe() 或构造函数设置声明性描述,根据此描述任务树将执行包含的任务并处理完成的任务。
当任务树为空时,即使用默认构造函数构建时,对 start()
的调用为无操作,并会发出相关警告信息。
否则,当任务树已运行时,对 start() 的调用将被忽略,并会发出相关警告信息。
否则,将启动任务树。
启动的任务树可能会同步完成,例如当主组的启动处理器返回 SetupResult::StopWithError 时。因此,在调用 start()
之前应建立与 done 信号的连接。使用 isRunning() 来检测在调用 start()
之后任务树是否仍在运行。
任务树实现依赖于运行的循环。确保在调用此方法时,有一个 QEventLoop 或 QCoreApplication 或其子类正在运行(或准备运行)。
另请参阅TaskTree(const Tasking::Group &), setRecipe(), isRunning() 和 cancel()。
[信号]
void TaskTree::started()
当任务树启动时,会发出此信号。该信号的发出会同步地由具有初始 0
值的 progressValueChanged() 信号跟随。
int TaskTree::taskCount() const
返回存储配方中包含的异步任务的数量。
注意:返回的数字不包括 Sync 任务。
注意:使用 withTimeout() 设置的任何任务或组都会通过 1
增加总任务数。
另请参阅setRecipe() 和 progressMaximum()。
©2024 The Qt Company Ltd. 本文档中的文档贡献享有各自所有者的版权。本提供的文档是根据由自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款授予的。Qt 及相关标志是芬兰的 Qt 公司及其在全世界范围内的商标。所有其他商标均为其各自所有者的财产。