对于 Rust 中的多个可变引用,同步如何成为问题?

Posted

技术标签:

【中文标题】对于 Rust 中的多个可变引用,同步如何成为问题?【英文标题】:How is synchronizing is a problem for multiple mutable references in Rust? 【发布时间】:2021-12-20 13:59:27 【问题描述】:

我在阅读 Rust 文档第 4 节时看到了这样的代码:

let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;

println!(", ", r1, r2);

所以文档说你不能在 Rust 中拥有多个可变引用。好的,有道理,但文档说如果你可以使用会发生三种行为,其中之一是:

没有用于同步访问数据的机制。

是否需要同步机制?我的意思是我们已经使用了指向堆的指针或指向堆的另一个指针。

我的意思是在这个图中,假设我们有 s2s3 作为对 s1 的可变引用。 s1 已经有一个指向堆的指针,所以 s2s3 有指向 s1 的指针。当我们更改s2s3 时,堆中的内存不会发生变化吗?

let mut s1 = String::from("Hello");
let s2 = &mut s1;
s2.push_str(", world");

在这里,s1 指向的堆中的内存已更改,因此s3 已经指向该内存,所以它不是已经同步了吗?

我有一个问题,为什么我们不应该使用多个可变引用。我只是假设我们可以。 Rust 说没有同步访问数据的机制。我的问题是,我们已经从每个引用中获得了指向堆的指针,所以当我们更改堆中的值时,它们都会同步,因为它们不是值,它们只是指向堆的指针,并且堆中的值被更改?

【问题讨论】:

指针不提供同步。 这是一个规则,没有什么了。 一些很好的理由:manishearth.github.io/blog/2015/05/17/… 【参考方案1】:

想象一下,如果允许以下情况:

let mut maybe_five = Some(5);
let mut zero = 0;

// first mutable borrow
let ref_five = &mut maybe_five;

// second mutable borrow
// number_ref is a reference inside maybe_five's Some
let number_ref = match &mut maybe_five 
    Some(ref mut five) => five,
    _ => &mut zero,
;

// invalidate number_ref by making the value it points to invalid
*ref_five = None;

// now we write into a None???
*number_ref = 10;

我们将能够在安全生锈的情况下执行各种未定义的行为。

【讨论】:

不会说其他允许这样做的语言? 不,我明白为什么我们不应该有多个可变引用。但我只是想知道我提到的行为:同步。我的问题是,为什么我们需要一种机制来同步可变引用如果我们可以在 Rust 中拥有该功能 @DoğukanAkkaya 该功能确实存在于 rust 中:doc.rust-lang.org/std/sync/struct.Mutex.html 同步不是默认的原因是它在计算上并不便宜。例如,互斥锁会锁定。而且还因为如果我们没有多个可变引用,则没有必要。 这就是我真正要问的。同步不是引用的默认行为吗?当堆中的值发生变化时,所有的引用都会同步,因为它们只是指针,而不是值。我的意思是 x 指向 0x00 地址,y 指向 0x00 地址,z 拥有该值。当z 更改xy 时已经同步了对吗?我只是不明白为什么同步是使用多个可变引用的问题之一。我了解这种方法的其他问题,但不是那样。

以上是关于对于 Rust 中的多个可变引用,同步如何成为问题?的主要内容,如果未能解决你的问题,请参考以下文章

Rust 中的可变引用传递

Rust 编译器不期望一个可变引用,而应该期望一个可变引用

如何在 Rust 中传递对可变数据的引用?

“不能返回引用临时值的值”和 Rust 中的内部可变性

如何在Rust中修改向量的元素?

为啥在 Rust 中将 const 引用直接转换为可变引用无效?