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

Rust异步函数取出Vec<Client>时遭遇生命周期错误求助

123 | }
| -
| |
| completion_queues dropped here while still borrowed
| borrow might be used here, when out is dropped and runs the Drop code for type Vec
|
= note: values in a scope are dropped in the opposite order they are defined

运行环境为Tokio,`ClientConfig`和`Client`是自定义结构体,`ProtectionDomain`与`Context`来自RDMA库,相关代码如下:

## 异步函数代码
```rust
pub async fn connect_to_clients<'a>(
    config: ClientConfig,
    ctx: Arc<Context>,
    pd: Arc<ProtectionDomain<'_>>,
    mut out: Vec<Client<'a>>,
) {
    info!("Running client mode.");

    let completion_queues: Vec<CompletionQueue> = config
        .targets
        .iter()
        .enumerate()
        .map(|(i, _)| ctx.create_cq(1, i.try_into().unwrap()).unwrap())
        .collect();

    let mut i = 0;
    for c in config.targets {
        out.push(Client::new(&pd, &completion_queues[i], c.clone(), config.frame_size).await);
        i += 1;
    }
}

Config.rs代码

use serde::Deserialize;

#[derive(Deserialize, Debug)]
pub struct ClientConfig {
  pub targets: Vec<String>,
  pub frame_size: usize,
}

client.rs代码

pub struct Client<'a> {
  qp: QueuePair<'a>,
  memory_manager: MemoryManager,
}

MemoryManager代码

pub struct MemoryManager {
    pub mr: Arc<Mutex<MemoryRegion<u8>>>,
}

解决方案

问题根源

completion_queues是函数内部创建的局部变量,生命周期仅限当前函数作用域,但Client实例持有了它的引用。而传入的out向量生命周期'a远长于completion_queues,函数结束时completion_queues被销毁,Client的引用就会变成悬空引用,触发生命周期错误。

解决步骤

核心思路是让CompletionQueue的生命周期与Client保持一致,最常用的方案是用Arc包裹CompletionQueue,让Client持有Arc而非裸引用:

  1. 修改Client结构体:
    调整Client定义,让它持有Arc<CompletionQueue>(需确认RDMA库的QueuePair支持接受Arc包裹的CQ,或调整Client::new的参数适配):

    pub struct Client {
      qp: QueuePair,
      memory_manager: MemoryManager,
      cq: Arc<CompletionQueue>, // 用Arc持有CQ,确保生命周期同步
    }
    
  2. 修改异步函数:
    创建Arc包裹的CompletionQueue,并传递给Client:

    pub async fn connect_to_clients(
        config: ClientConfig,
        ctx: Arc<Context>,
        pd: Arc<ProtectionDomain<'_>>,
        mut out: Vec<Client>,
    ) {
        info!("Running client mode.");
    
        let completion_queues: Vec<Arc<CompletionQueue>> = config
            .targets
            .iter()
            .enumerate()
            .map(|(i, _)| Arc::new(ctx.create_cq(1, i.try_into().unwrap()).unwrap()))
            .collect();
    
        let mut i = 0;
        for c in config.targets {
            out.push(Client::new(&pd, &completion_queues[i], c.clone(), config.frame_size).await);
            i += 1;
        }
    }
    

备选方案

如果RDMA库的QueuePair必须使用裸引用,可将completion_queues与Client封装到同一个父结构体中,确保二者生命周期绑定。但Arc方案更灵活,适配异步场景下的所有权管理需求。


内容的提问来源于stack exchange,提问作者Joep Van Diessen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 07:19:57