Sal*_*ler 1 multithreading thread-safety rust
假设我有一个类似的结构:
pub struct MyStruct {
f: Arc<dyn Fn(Vec<f64>) -> Vec<f64>>,
}
impl MyStruct {
pub fn new(f: Arc<dyn Fn(Vec<f64>) -> Vec<f64>>) -> MyStruct {
MyStruct { f }
}
pub fn start(&self) {
for _ in 0..5 {
let f = self.f.clone();
thread::spawn(move || {
let v: Vec<f64> = get_random_vector();
let v = (f)(v);
// do something with v
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
我收到一个错误,指出该函数无法在线程之间安全地共享,因为该dyn Fn(Vec<f64>) -> Vec<f64>)类型未实现Sync。
我可以做一个黑客,我可以将 包装在 Wrapper 结构中,然后使用 usingArc<dyn Fn(Vec<f64>) -> Vec<f64>标记包装器。但我想知道是否有比这更好的解决方案。Syncunsafe impl
现在,由于函数位于 an 内部,Arc我们可以保证函数值是不可变的。
我还可以保证对于 的任何实例,向量的大小始终保持不变MyStruct。可能是 2、3,也n可能是相同的。所以向量的大小是恒定的。所以函数大小实际上是常数。
事实上,如果Vec<f64>我不使用&[f64]and [f64],该函数仍然不会实现Send,即使切片具有确定的大小。
那么为什么该函数不能在线程之间共享,我该怎么做才能在线程之间共享它呢?
为了将 an 发送Arc到另一个线程,Arc需要实现Send. 如果您查看文档,Arc您会发现它有
impl<T> Send for Arc<T> where
T: Send + Sync + ?Sized {}
Run Code Online (Sandbox Code Playgroud)
这意味着要使您的代码正常工作,您的T( dyn Fn(Vec<f64>) -> Vec<f64>) 需要实现Send和Sync。
由于您的类型是一个特征对象,因此您需要做的是声明,例如
pub struct MyStruct {
f: Arc<dyn Fn(Vec<f64>) -> Vec<f64> + Sync + Send>,
}
impl MyStruct {
pub fn new(f: Arc<dyn Fn(Vec<f64>) -> Vec<f64> + Sync + Send>) -> MyStruct {
MyStruct { f }
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
如图所示,该T类型实现了所有这三个特征:
Fn(Vec<f64>) -> Vec<f64>SyncSend如果没有该Sync + Send特征,您的f函数可能会捕获对 a 的引用Cell,这会导致竞争条件,因为多个线程可能会同时尝试更新单元格的值。您的代码很可能没有这样做,但是您的start函数无法知道这一点,除非您告诉它f受到足够的限制以不允许这样做。
| 归档时间: |
|
| 查看次数: |
2145 次 |
| 最近记录: |