From b01c2fd958a6f3e6d340f8650f9aadf12adb8ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=A2=E5=B3=B0=E7=91=9E?= Date: Fri, 9 Oct 2026 15:09:11 +0800 Subject: [PATCH] fix: join the capture thread when the move fails in example 07 07_vel_jitter_trace starts a capture thread before the move and joins it after. If the move throws -- a refused cartesian plan or a timeout are both normal operating conditions -- the stack unwinds past the join and the joinable std::thread is destroyed, so std::terminate fires: the example core-dumps (exit 134) and, because stdout is block-buffered on a pipe, the error message is lost too. Stop and join the capture thread in a catch block before rethrowing, so the failure surfaces through the normal error path. --- examples/07_vel_jitter_trace.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/07_vel_jitter_trace.cpp b/examples/07_vel_jitter_trace.cpp index 98871b3..7b4d6b2 100644 --- a/examples/07_vel_jitter_trace.cpp +++ b/examples/07_vel_jitter_trace.cpp @@ -166,10 +166,22 @@ int main(int argc, char** argv) { }); // ---- 路②: 开 300Hz 固件日志, 然后发运动 ---- - arm.log().start(LOG_TICKS); - const double t_move0 = now_s(); - const CartPlan plan = arm.move_l(goal, args.speed); - const double move_s = now_s() - t_move0; + // ⚠ 线程必须在**所有路径**上 stop+join: move_l 抛异常 (固件拒绝规划、超时 + // 都是正常工况) 时若不收线程, `std::thread` 析构会对 joinable 线程直接 + // `std::terminate` —— 实测就是 core dump (exit 134), 且 stdout 还在块缓冲里, + // 错误信息也一起丢。 + CartPlan plan{}; + double move_s = 0.0; + try { + arm.log().start(LOG_TICKS); + const double t_move0 = now_s(); + plan = arm.move_l(goal, args.speed); + move_s = now_s() - t_move0; + } catch (...) { + stop.store(true); + grabber.join(); + throw; + } stop.store(true); grabber.join();