从互斥锁中借用数据“借来的值活得不够长" [英] Borrow data out of a mutex "borrowed value does not live long enough"

查看:40
本文介绍了从互斥锁中借用数据“借来的值活得不够长"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎样才能返回一个迭代器对自身包含在结构中的互斥体中的数据进行迭代.编译器给出的错误是借来的值活得不够长".

How can I return an iterator over data within a mutex which itself is contained within a struct. The error the compiler gives is "borrowed value does not live long enough".

如何让值的生命周期扩展到外部作用域?

How do I get the lifetime of the value to extend into the outer scope?

这是我试图实现的最小演示.

Here is a minimal demo of what I am trying to achieve.

use std::sync::{Mutex, Arc};
use std::vec::{Vec};
use std::slice::{Iter};

#[derive(Debug)]
struct SharedVec {
  pub data: Arc<Mutex<Vec<u32>>>,
}

impl SharedVec {
  fn iter(& self) -> Iter<u32> {
    self.data.lock().unwrap().iter()
  }
}

fn main() {

  let sv = SharedVec {
    data: Arc::new(Mutex::new(vec![1, 2, 3, 4, 5]))
  };

  for element in sv.data.lock().unwrap().iter() {  // This works
    println!("{:?}", element);
  }

  for element in sv.iter() {  // This does not work
    println!("{:?}", element);
  }
}

Rust 游乐场链接:http://is.gd/voukyN

Rust playground link: http://is.gd/voukyN

推荐答案

你不能完全按照你在这里写的方式去做.

You cannot do it exactly how you have written here.

Rust 中的互斥锁使用 RAII 模式进行获取和释放,也就是说,当您调用它的相应方法时,您会获取一个互斥锁,该方法返回一个特殊的保护值.当这个守卫超出范围时,互斥锁被释放.

Mutexes in Rust use RAII pattern for acquisition and freeing, that is, you acquire a mutex when you call the corresponding method on it which returns a special guard value. When this guard goes out of scope, the mutex is released.

为了使这种模式安全,Rust 使用了借用系统.只能通过lock()返回的guard来访问互斥锁内部的值,而且只能通过引用来访问——MutexGuard<T>实现了Deref<Target=T>DerefMut,这样你就可以得到 &T&mut T摆脱它.

To make this pattern safe Rust uses its borrowing system. You can access the value inside the mutex only through the guard returned by lock(), and you only can do so by reference - MutexGuard<T> implements Deref<Target=T> and DerefMut<Target=T>, so you can get &T or &mut T out of it.

这意味着您从互斥值中获得的每个值都必须将其生命周期与守卫的生命周期相关联.但是,在您的情况下,您试图返回 Iter<u32>,其生命周期参数与 self 的生命周期相关联.以下是 iter() 方法的完整签名,没有生命周期参数省略,其主体带有显式临时变量:

This means that every value you derive from a mutexed value will necessarily have its lifetime linked to the lifetime of the guard. However, in your case you're trying to return Iter<u32> with its lifetime parameter tied to the lifetime of self. The following is the full signature of iter() method, without lifetime parameters elision, and its body with explicit temporary variables:

fn iter<'a>(&'a self) -> Iter<'a, u32> {
    let guard = self.data.lock().unwrap();
    guard.iter()
}

这里 guard.iter() 结果的生命周期与一个 guard 相关联,它严格小于 'a 因为 guard 只存在于方法体的范围内.这违反了借用规则,因此编译器因错误而失败.

Here the lifetime of guard.iter() result is tied to the one guard, which is strictly smaller than 'a because guard only lives inside the scope of the method body. This is a violation of borrowing rules, and so the compiler fails with an error.

iter() 返回时,guard 被销毁并释放锁,所以 Rust 实际上阻止了你犯真正的逻辑错误!C++ 中的相同代码会编译并且行为不正确,因为您将访问受保护的数据而不锁定它,至少会导致数据竞争.又一次展示了 Rust 的强大功能 :)

When iter() returns, guard is destroyed and the lock is released, so Rust in fact prevented you from making an actual logical error! The same code in C++ would compile and behave incorrectly because you would access protected data without locking it, causing data races at the very least. Just another demonstration of the power of Rust :)

我认为如果没有围绕标准类型的讨厌的黑客攻击或样板包装,你将无法做你想做的事.我个人认为这很好——你必须尽可能明确地管理你的互斥,以避免死锁和其他令人讨厌的并发问题.而 Rust 已经让您的生活变得更加轻松,因为它通过其借用系统强制消除数据竞争,这正是保护系统行为如上所述的原因.

I don't think you'll be able to do what you want without nasty hacks or boilerplate wrappers around standard types. And I personally think this is good - you have to manage your mutexes as explicit as possible in order to avoid deadlocks and other nasty concurrency problems. And Rust already makes your life much easier because it enforces absence of data races through its borrowing system, which is exactly the reason why the guard system behaves as described above.

这篇关于从互斥锁中借用数据“借来的值活得不够长"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆