首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >向线程传递函数引用

向线程传递函数引用
EN

Stack Overflow用户
提问于 2019-12-22 06:21:43
回答 1查看 1.3K关注 0票数 1

如果我有一个结构,就像:

代码语言:javascript
运行
复制
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
        });
      }
   }
}

我收到一个错误,即由于dyn Fn(Vec<f64>) -> Vec<f64>)类型没有实现Sync,所以函数不能在线程之间安全地共享。

在可以将Arc<dyn Fn(Vec<f64>) -> Vec<f64>包装在包装结构中,然后使用Sync使用unsafe impl标记包装的地方,就可以进行黑客攻击。但我想知道是否有比这更好的解决办法。

现在,由于函数在Arc中,所以我们可以保证函数值是不可变的。

我还可以保证,对于MyStruct的任何实例,向量的大小都是恒定的。它可能是2,3,或n,但它将是相同的。所以向量的大小是恒定的。所以函数的大小是事实上的常数。

事实上,如果我不使用Vec<f64>,而是使用&[f64][f64],那么这个函数仍然不会实现Send,即使片有一定的大小。

那么,为什么不能在线程之间共享这个函数,我能做些什么来在线程之间共享它呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-22 07:25:54

为了将Arc发送到另一个线程,Arc需要实现Send。如果你看一下the docs for Arc,你会发现它有

代码语言:javascript
运行
复制
impl<T> Send for Arc<T> where
    T: Send + Sync + ?Sized {}

这意味着,要使代码工作,T (dyn Fn(Vec<f64>) -> Vec<f64>)需要实现SendSync

因为你的类型是一个特征对象,所以你需要做的就是声明。

代码语言:javascript
运行
复制
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 }
   }
   // ...
}

与之相同,T类型实现了所有这三个特性:

  • Fn(Vec<f64>) -> Vec<f64>
  • Sync
  • Send

如果没有Sync + Send特性,您的f函数就可以捕获对Cell的引用,这将导致竞争条件,因为多个线程可能同时尝试更新单元格的值。您的代码很可能没有这样做,但是您的start函数无法知道这一点,除非您告诉它f受到了足够的限制,不允许这样做。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59442080

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档