【问题标题】:Why do Rust's `Atomic*` types use non-mutable functions to mutate the value?为什么 Rust 的 `Atomic*` 类型使用非可变函数来改变值?
【发布时间】:2016-03-05 06:18:34
【问题描述】:

我注意到 Rust 的 Atomic* 结构具有修改值的函数,例如 fetch_add。例如,我可以编写这个程序:

use std::sync::atomic::{AtomicUsize, Ordering};

struct Tester {
    counter: AtomicUsize
}

impl Tester {
    fn run(&self) {
        let counter = self.counter.fetch_add(1, Ordering::Relaxed);
        println!("Hi there, this has been run {} times", counter);
    }
}

fn main() {
    let t = Tester { counter: AtomicUsize::new(0) };
    t.run();
    t.run();
}

这编译并运行良好,但如果我将AtomicUsize 更改为普通整数,由于可变性问题,它将(正确)无法编译:

struct Tester {
    counter: u64
}

impl Tester {
    fn run(&self) {
        self.counter = self.counter + 1;
        println!("Hi there, this has been run {} times", self.counter);
    }
}

【问题讨论】:

标签: rust


【解决方案1】:

如果它以这种方式工作,它不会很有用。使用&mut 引用,一次只能存在一个,而当时没有& 引用,因此整个操作的原子性问题将毫无意义。

另一种看待它的方式是&mut唯一 引用,而& 别名 引用。对于普通类型,只有在具有唯一引用的情况下才能安全地发生突变,但原子类型都是关于突变(通过替换)而不需要唯一引用。

&&mut 的命名一直令人担忧,社区中充满了恐惧、不确定和怀疑,Focusing on Ownership 等文件解释了实际情况。该语言最终与&&mut 保持一致,但&mut 实际上是关于唯一性而不是可变性(只是大多数时候两者是等价的)。

【讨论】:

  • Rust 的“内部可变性”比 C++ 中的 const_cast 更为普遍。也许用(不)可变性来命名它是一个糟糕的决定。
  • 我使用 atomic 进行低级无锁操作。但是,当我用Arc 包装高级结构时,我不能使用它的&mut 方法。我最终得到了一个解决方案,将高级 API 的所有第一个参数设置为&self(因为Arc 自动将deref 设置为&self)。它有效,但在可变性方面尚不清楚。
猜你喜欢
  • 2017-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-27
  • 2019-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多