SDKC++ SDK

运行方式

当前线程、后台线程与手动 update 三种运行模型。

当前版本 · 1.4.0

运行方式

本章只适用于需要持续推进 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。