Rust 在闭包之间共享圆弧
我正在尝试编写一个简单的tcp服务器,用于读取和广播消息。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:
我用的是东京,但我认为这更像是一个普遍的问题 我有一个共享状态的弧:
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();
}