You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何并行创建并运行多个Drake Solver实例?

问题:多线程/多进程中运行多个Drake Solver实例的实现方案

我希望在多线程乃至多进程中运行多个solver。目前我通过for循环创建线程,代码如下:

for (...) {
    pthread_t pid;
    Args args;
    args.solver = solver???
    pthread_create(&pid, NULL, &func, (void*)&args);
}

在定义solver时,我尝试了多种方法,但均未成功:

  • 首先,调用const auto solver = drake::solvers::MakeSolver(solver_id);后将solver.get()传入每个线程的args。代码可编译运行,但在drake::solvers::SnoptSolver::DoSolve中出现terminate called recursively错误。发现MakeSolver返回指向kKnownSolvers中单个solver实例的unique_ptr,推测是多线程调用同一实例的DoSolve导致了该问题。
  • 随后尝试创建多个solver实例:调用StaticSolverInterface::Make<SnoptSolver>()失败,因为它定义在未命名命名空间中,仅能在该文件内访问;调用const auto solver = drake::solvers::MakeSolver(solver_id);并复制solver指向的SolverInterface也不可行,因为SolverInterface不可移动或复制。

请问我的需求是否可行?若可行,该如何实现?


解决方案

你的需求完全可行,核心是为每个线程/进程创建独立的Solver实例,避免并发访问同一实例引发的线程安全问题。以下是具体实现方案:

1. 线程内创建专属Solver实例(推荐)

不要在主线程创建单个Solver后共享给所有线程,而是在每个线程的入口函数内部调用drake::solvers::MakeSolver(solver_id),为线程生成专属的Solver实例。这样每个线程拥有独立的Solver状态,不会出现并发冲突。

示例代码调整如下:

// 线程入口函数
void* func(void* arg) {
    // 在线程内部创建专属的Solver实例
    const auto solver = drake::solvers::MakeSolver(solver_id);
    // 使用solver执行求解任务
    const auto result = solver->DoSolve(...);
    // ... 后续处理逻辑
    pthread_exit(NULL);
}

// 主线程创建线程
for (...) {
    pthread_t pid;
    pthread_create(&pid, NULL, &func, NULL);
    // 若需传递任务参数,可将参数分配在堆上,避免栈内存被回收
}

2. 主线程创建多实例并转移所有权

如果需要在线程启动前准备好Solver实例,可以为每个线程单独调用MakeSolver,然后通过unique_ptr转移所有权到线程中(注意SolverInterface不可复制,必须用所有权转移)。

示例代码:

// 定义带所有权转移的参数结构体
struct Args {
    std::unique_ptr<drake::solvers::SolverInterface> solver;
    // 可添加其他任务参数
};

void* func(void* arg) {
    // 接管参数的所有权
    auto args = std::unique_ptr<Args>(static_cast<Args*>(arg));
    auto& solver = *args->solver;
    // 执行求解任务
    const auto result = solver.DoSolve(...);
    // ... 后续处理
    pthread_exit(NULL);
}

// 主线程逻辑
for (...) {
    pthread_t pid;
    auto args = std::make_unique<Args>();
    // 为当前线程创建独立的Solver实例
    args->solver = drake::solvers::MakeSolver(solver_id);
    // 转移参数所有权到线程,避免主线程回收内存
    pthread_create(&pid, NULL, &func, args.release());
}

3. 多进程场景的实现

多进程场景下,每个进程拥有独立的内存空间,直接在每个进程内调用MakeSolver创建实例即可,无需考虑跨进程的共享问题,实现逻辑比多线程更简单。

失败原因说明

  • 共享同一Solver实例:Drake的Solver实现(如SnoptSolver)大多不是线程安全的,多线程并发调用同一实例的DoSolve会破坏内部状态,触发递归终止错误。
  • 无法复制SolverInterface:该接口设计为不可复制、不可移动,目的是避免状态拷贝带来的一致性问题,因此必须通过所有权转移或线程内创建的方式使用。

内容的提问来源于stack exchange,提问作者alvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:35:45