你怎么发送Vec切片到生锈的任务?

时间:2014-10-21 01:57:53

标签: rust

所以,这不起作用:

use std::comm;

#[deriving(Show)]
struct St { v: u8 }

fn main() {

  let mut foo:Vec<St> = Vec::new();
  for i in range(0u8, 10) {
    foo.push(St { v: i });
  }

  {
      let mut foo_slice = foo.as_mut_slice();
      let (f1, f2) = foo_slice.split_at_mut(5);

      let (sl, rx):(Sender<Option<&mut [St]>>, Receiver<Option<&mut [St]>>) = comm::channel();
      let (sx, rl):(Sender<bool>, Receiver<bool>) = comm::channel();

      spawn(proc() {
        loop {
          let v = rx.recv();
          match v {
            Some(v) => {
                v[0].v = 100u8;
                sx.send(true);
            },
            None => {
                sx.send(false);
                break;
            }
          }
        }
      });

      sl.send(Some(f1));
      sl.send(Some(f2));
      sl.send(None);

      println!("{}", rl.recv());
      println!("{}", rl.recv());
      println!("{}", rl.recv());
  }

  println!("{}", foo);
}

...因为:

sl.send(Some(f1));
sl.send(Some(f2));
sl.send(None);

推断变量f1和f2必须是'静态的,因为任务可能比它正在运行的函数更长。这反过来意味着foo必须是'静态的,而不是'a,这是main的生命周期( )。

因此有些奇怪的错误:

<anon>:14:27: 14:30 error: `foo` does not live long enough
<anon>:14       let mut foo_slice = foo.as_mut_slice();
                                    ^~~
note: reference must be valid for the static lifetime...
<anon>:6:11: 46:2 note: ...but borrowed value is only valid for the block at 6:10
<anon>:6 fn main() {
<anon>:7  
<anon>:8   let mut foo:Vec<St> = Vec::new();
<anon>:9   for i in range(0u8, 10) {
<anon>:10     foo.push(St { v: i });
<anon>:11   }

所以,为了解决这个问题,我认为使用Box&lt; Vec&lt; Foo&gt;&gt;可能是解决方案,但即使这样,创建的切片也将具有本地生命周期。

我可以使用不安全的代码来转换生命周期(这确实有效),但有没有办法安全地做同样的事情?

围栏:http://is.gd/WQBdSB

1 个答案:

答案 0 :(得分:8)

Rust会阻止您对多个任务中的相同值进行可变访问,因为这会导致数据争用。具体来说,任务不能将指针(包括切片)借用到另一个任务所拥有的值。

要允许多个任务访问同一个对象,您应该使用Arc<T>。要提供对该对象的可变访问权限,请在ArcArc<RefCell<T>>中添加RefCell<T>。至于那个T,你不能像我刚才解释的那样使用切片类型。我建议您创建2个不同的Arc<RefCell<Vec<St>>>个对象,在频道上发送Arc<RefCell<Vec<St>>>的克隆,并在任务完成后加入Vec

通常,在进行并行算法时,应避免改变共享状态。这会导致性能不佳,因为系统需要使内核中的内存缓存无效。如果可能,请考虑让任务分配并保持其结果直到完成,并通过通道发送完整的结果,而不仅仅是bool

修改

我们可以根据所有权重新制定您的初始计划,以了解为什么它不合理。调用main的堆栈框架拥有foo Vecfoo_slicef1f2借用Vec。你产生了一个任务。 该任务可能比main 的调用框架更长,甚至比生成它的任务更长。因此,发送对受限于堆栈帧的值的引用是非法的。这就是为什么借用指针({1}}除外)不符合Send

拳击&'static T不会改变任何内容,因为堆栈帧仍然拥有Vec,因此从函数返回将删除框及其内容。

编译器无法验证任务是否不会超过您发送对任务的引用值的所有者。如果您确定该任务将在您提供的引用无效之前终止,您可以使用transmute来欺骗生命周期,但这是不安全的。