我正在考虑将拥有一些线程安全值的闭包传递给生成的线程的可能性。然后该线程将能够仅通过知道签名来调用某些东西,而其内容对它来说是不透明的。
我写了一个简单的测试,令人惊讶的是,它成功了。为了使闭包可以在线程内调用,Rust 编译器建议为其添加std::marker::Send
和'static
约束。第一个适用是有道理的——闭包捕获的所有值都是Send
,但静态生命周期要求被认为已满足,这让我很困惑,因为我假设编译器会认为闭包及其拥有的值具有特定的非静态生命周期。
我想了解原因。代码如下:
use std::sync::{mpsc::{Receiver, Sender}, Arc, Mutex};
fn main() {
let tx = start_thread();
// can also run in a loop with a sleep in between or whatever
let _ = tx.send(String::from("Something"));
}
fn start_thread() -> Sender<String> {
// Something created on the main thread that we pass to the spawned thread
// inside the closure -- the spawned thread has no direct knowledge of it
let closure_owned_value: Arc<Mutex<f32>> = Arc::new(Mutex::new(42.0));
// A closure we want to be called by the spawned thread,
// but not defined there -- this is considered 'static somehow?
let on_thread_callback = move |msg: String| {
println!("Got back message from thread: {:?}, owned value: {:?}", msg, closure_owned_value);
};
let (tx, rx) = std::sync::mpsc::channel();
spawn_thread_with_callback(rx, on_thread_callback);
tx
}
fn spawn_thread_with_callback<F>(
rx: Receiver<String>,
callback: F
) -> std::thread::JoinHandle<()>
where
F: Fn(String) -> () + std::marker::Send + 'static
{
std::thread::spawn(move || {
/* Run an infinite loop as long as channel is open. */
while let Ok(message) = rx.recv() {
println!("Thread received message: {:?}", message);
callback(String::from("Hello back from thread!"));
}
})
}