运行方式
当前线程、后台线程与手动 update 三种运行模型。
运行方式
本章只适用于需要持续推进 Retargeting 或自动重连等后台工作的应用。只读取原始
pose/IMU 时不需要选择运行方式:成功调用 start() 后数据就会随有效设备帧发布。
需要调度能力时,在当前线程、后台线程和手动 update 3 种互斥运行模式中选择一种。
next() 和 C++20 coroutine 是单次等待数据的方式,不是第四种运行模式。
当前线程持续运行
run_forever() 在当前线程运行,适合生命周期简单的命令行程序:
glove.start();
glove.run_forever();run_forever() 适合当前线程持续运行的程序。公开命令行示例按 Ctrl+C 结束进程;需要由应用主动停止时,使用下面的后台线程模式。
后台线程运行
当主线程必须继续运行 UI、应用事件循环或安全停止协调时,使用:
glove.run_background();
// 主线程处理其他工作。
glove.request_stop();
glove.join();join() 等待后台运行完成并报告运行错误。run_background() 不会隐式连接或启动设备。
手动 update
应用拥有自己的调度循环时,持续调用 update() 执行一次 SDK 任务调度:
const auto update = glove.update();
do_application_work();
if (update.has_next_task()) {
const auto result = update.sleep();
}UpdateResult 提供 tick()、ran_task_count() 与 has_next_task()。sleep() 根据当前时刻等待后续工作,返回 SleepResult::ready、stopped 或 no_tasks。每个 update result 的等待
token 只能使用一次。原始 pose/IMU 随设备帧发布,不依赖 update()。
阻塞等待与取消
next() 返回一个 move-only NextOperation<T>,等待注册成功后的下一条数据:
auto pending = device.pose().next();
auto sample = pending.get();next() 可以在 start() 后使用;持续处理数据仍优先使用启动前注册的 subscribe()。
IMU 的等待方式与 pose 相同。读取方式总览见 数据来源与读取方式。
get() 会阻塞到数据到达或操作终止,并在返回前完成内部订阅清理。原始 pose/IMU 在
start() 后可以直接唤醒等待;等待 Retargeting 输出时,必须由后台模式或其他线程推进
SDK 调度。同步取消使用 cancel():
auto pending = device.pose().next();
pending.cancel();
try {
pending.get();
} catch (const std::system_error& error) {
if (error.code() != std::errc::operation_canceled) {
throw;
}
}NextOperation<T> 只能消费一次。对移动后或已消费的 operation 再调用会抛出 LifecycleError。
C++20 coroutine
额外链接 qnbot::core_coro 并包含 <qnbot/coro.hpp> 后,可以把已有的单次等待改为 co_await qnbot::coro::next(...):
qnbot::Sample<qnbot::GlovePose> sample =
co_await qnbot::coro::next(
device.pose().next(), executor, stop_token);executor 是 std::shared_ptr<qnbot::coro::DeferredExecutor>。它的 post() 必须满足以下约定:
- 接收每个 task 一次,并最终执行一次。
- 快速返回,不等待 task 执行完成。
- 不在调用
post()的 callback 线程内联执行 task。 post()不抛异常。
传入的 NextOperation<T> 仍然只能消费一次。已请求停止的 std::stop_token 会得到 std::errc::operation_canceled。
应用必须保证 coroutine 尚未完成或取消时,相关 executor、stop token 和任务对象保持有效;executor 回调仍在运行时不要并发销毁 coroutine。完整且可直接参考的真实手套生命周期处理见 async_runtime.cpp。