Rust 在闭包之间共享圆弧

Rust 在闭包之间共享圆弧,rust,Rust,我正在尝试编写一个简单的tcp服务器,用于读取和广播消息。 我用的是东京,但我认为这更像是一个普遍的问题 我有一个共享状态的弧: let state=Arc::new(Mutex::new(Shared::new(server_tx)); 稍后,我将生成2个线程,它们将使用对该状态的引用: let server = listener.incoming().for_each(move |socket| { // error[E0382]: capture of moved value:

我正在尝试编写一个简单的tcp服务器,用于读取和广播消息。
我用的是东京,但我认为这更像是一个普遍的问题

我有一个共享状态的弧:
let state=Arc::new(Mutex::new(Shared::new(server_tx));

稍后,我将生成2个线程,它们将使用对该状态的引用:

let server = listener.incoming().for_each(move |socket| {
    // error[E0382]: capture of moved value: `state`
    process(socket, state.clone());
    Ok(())
}).map_err(|err| {
    println!("accept error = {:?}", err);
});

let receive_sensor_messages = sensors_rx.for_each(move |line| {
    println!("Received sensor message, broadcasting: {:?}", line);

    // error[E0597]: borrowed value does not live long enough
    // error[E0507]: cannot move out of borrowed content 
    for (_, tx) in state.clone().lock().unwrap().clients {
        tx.unbounded_send(line.clone()).unwrap();
    }
    Ok(())
}).map_err(|err| {
    println!("line reading error = {:?}", err);
});
()

据我所知,它试图告诉我的是,
state
在第一个闭包
listener.incoming().for_each(move | socket |{
中借用了
state
,所以当我在
sensors_rx.for_each(move | line |{
中再次尝试这样做时,它会说这是不可能的

我的问题是如何解决它?难道
Arc
不应该解决线程之间共享变量的问题吗? 我尝试了不同的
clone
组合(在闭包外进行克隆,然后在闭包内再次进行
clone
),但都没有成功


干杯!

对于每个闭包,您必须提供自己的
Arc
,因此您必须事先克隆
您的
Arc

let state = Arc::new(Mutex::new(Shared::new(server_tx)));
let state1 = Arc::clone(&state);
let state2 = Arc::clone(&state);

let server = listener.incoming().for_each(move |socket| {
    process(socket, state1.clone());
    Ok(())
});

let receive_sensor_messages = sensors_rx.for_each(move |line| {
    println!("Received sensor message, broadcasting: {:?}", line);
    let shared = state2.lock().unwrap();
    for (_, tx) in &shared.clients { // better: `for tx in shared.clients.values()`
        tx.unbounded_send(line.clone()).unwrap();
    }
    Ok(())
});
您可以在这里省略
state1
,但我发现这样做更干净


原因是,您将值
状态移动到第一个闭包中,因此您不能在第二个闭包中使用它,因为它已经移动了(有意义,不是吗?)。

本质上,您的问题可以归结为

现在,这里的第一个问题是,
示例
被移动。也就是说,一旦我们越过
(1)
,原始的
示例
就被认为是从中移动的。相反,我们需要先
克隆
,然后
移动

    let example = Arc::new(Mutex::new(Bar));
    let local_state = example.clone();
    std::thread::spawn(move ||{
        let _ = local_state; // now fine!
    });
另一个错误源于短寿命的
Arc
。本质上,它的寿命只够你在底层的
互斥锁上锁定
。虽然我们知道至少有一个
Arc
指向内存,但编译器无法证明这一点。然而,如果我们去掉
克隆()
很好:

    let local_state = example.clone();        
    std::thread::spawn(move ||{
        foo(&local_state.lock().unwrap());
    });
但是,您也可以通过使用容器的内容(客户机<代码>来循环容器。相反,请在容器中使用<代码>和<代码>,例如<代码>和本地状态().unwrap().clients

您可以在下面找到完整的固定代码:


你能试着提供一个MCVE而不是一个完整的程序吗?发生“无法移出借用的内容”的原因是
for
循环使用了它的参数(例如,请参见)。将该行更改为
for(uu,tx)in&state.lock().unwrap()。客户端
会将问题归结为
Arc
问题。
    let local_state = example.clone();        
    std::thread::spawn(move ||{
        foo(&local_state.lock().unwrap());
    });
use std::sync::{Arc, Mutex};

struct Bar;

fn foo(_ : &Bar){
    println!("foo called");
}

fn main(){
    let example = Arc::new(Mutex::new(Bar));
    let local_state = example.clone();
    std::thread::spawn(move ||{
        let _ = local_state;
    });
    let local_state = example.clone();
    std::thread::spawn(move ||{
        foo(&local_state.lock().unwrap());
    }).join();
}