我想在线程之间共享一个函数引用,但 Rust 编译器说`dyn for<'r> std::ops::Fn(&'r std::string::String) -> std::string::String` cannot be shared between threads safely. 我很了解Send, Sync, 以及Arc<T>在线程之间共享“常规”值时,但在这种情况下,我无法理解问题所在。一个函数在程序运行期间有一个静态地址,因此我在这里看不到问题。
我怎样才能使这项工作?
fn main() {
// pass a function..
do_sth_multithreaded(&append_a);
do_sth_multithreaded(&identity);
}
fn append_a(string: &String) -> String {
let mut string = String::from(string);
string.push('a');
string
}
fn identity(string: &String) -> String {
String::from(string)
}
fn do_sth_multithreaded(transform_fn: &dyn Fn(&String) -> String) {
for i in 0..4 {
let string = format!("{}", i);
thread::spawn(move || {
println!("Thread {}: {}", i, transform_fn(&string))
});
}
}
Run Code Online (Sandbox Code Playgroud)
一个函数在程序运行期间有一个静态地址,因此我在这里看不到问题。
这对函数来说很好,但是你传递的是&dyn Fn, 并且它也可以是一个闭包或(在不稳定的 Rust 中)一个实现该特征的自定义对象。而且这个对象可能没有静态地址。所以你不能保证对象会比你产生的线程存活的时间长。
但这甚至不是编译器所抱怨的(还没有!)。它实际上是在抱怨它不知道是否允许您Fn从另一个线程访问。同样,与函数指针无关,但与闭包相关。
这是适用于您的示例的签名:
fn do_sth_multithreaded(transform_fn: &'static (dyn Fn(&String) -> String + Sync))
Run Code Online (Sandbox Code Playgroud)
注意'static生命周期界限和Sync界限。
但是,虽然静态生命周期适用于这种情况,但它可能意味着您永远无法发送闭包。为了使这项工作,您需要使用作用域线程系统(例如,从crossbeamcrate 中)以确保do_sth_multithreaded在返回之前等待线程完成。然后你可以放宽静态生命周期界限。