# 错误处理与线程安全
不同语言接口使用符合各自习惯的机制表示相同的主要错误类别。
## 错误对应关系
| 无效参数、handle 或长度 | `InvalidInput` 类别的 `Error` | `ValueError` | `dynibo::Error` | `DYNIBO_STATUS_INVALID_ARGUMENT` |
| URDF/模型失败 | `Model` 类别的 `Error` | `ModelError` | `dynibo::Error` | `DYNIBO_STATUS_MODEL_ERROR` |
| IK 数值失败或不收敛 | `Solver` 类别的 `Error` | `SolverError` | `dynibo::Error` | `DYNIBO_STATUS_SOLVER_ERROR` |
| ABI 边界捕获 panic | 原生 Rust 调用不适用 | `PanicError` | `dynibo::Error` | `DYNIBO_STATUS_PANIC` |
不要根据供人阅读的错误文本进行程序分支。Rust 提供 `ErrorCategory`,C 提供稳定状态值,
Python 提供异常类型,C++ 的 `Error::status()` 会保留 C 状态。
## C 错误消息
`dynibo_last_error_message()` 返回线程局部字符串。它在同一线程下一次可能失败的 dynibo
调用之前有效;成功调用会将其清空。如果消息需要跨越下一次调用,应复制字符串。
## 线程安全规则
- Rust `RobotModel` 不可变,可在线程间共享,无需加锁。
- 没有线程修改固定 `Robot` 的 base frame 时,可以读取不可变模型信息。
- 每个 Rust `Robot` 或 `FloatingRobot` 都拥有一个可变 workspace,计算方法需要可变访问;
每个并发计算应通过 `fork()` 创建独立实例。
- C 的每个并发计算需要独立的 typed workspace:固定基使用 `DyniboWorkspace`,浮动基使用
`DyniboFloatingWorkspace`。
- Python 会串行化同一 `Robot` 或 `FloatingRobot` 的方法;`fork()` 共享模型数据并创建
独立实例,可执行并行原生调用。
- C++ wrapper 没有内部锁;每个 worker 应使用独立 `dynibo::Robot` 或
`dynibo::FloatingRobot`。
- 其他线程使用 handle 时,绝不能销毁或移动所属对象。
## 错误恢复
关节状态、广义力、外载荷和 tool 位姿必须包含有限值。输入校验失败时,调用方提供的
计算输出 buffer 保持不变。有限载荷累加溢出属于求解错误;求解错误后的输出不保证有效,
只有成功返回后才能使用计算输出。
参数错误和求解器错误不会使 robot 或 workspace 失效,修正输入后可以再次调用。ABI
边界捕获 panic 可以防止 unwinding 穿过外部语言边界,但它表示意外的内部失败;决定
是否继续前,应记录错误消息和 dynibo 版本。