我想更好地理解以下 Rust 代码背后的语义:

use std::thread;

fn main() {
    let immutable = "I am not mutable";
    let mut mutable = "I am mutable";

    let handle1 = thread::spawn(move || {
        println!("Thread 1 says: {}", immutable);
    });

    let handle2 = thread::spawn(move || {
        println!("Thread 2 says: {}", immutable);
    });

    let handle3 = thread::spawn(move || {
        println!("Thread 3 says: {}", mutable);
        mutable = "go away";
    });

    let handle4 = thread::spawn(move || {
        println!("Thread 4 says: {}", mutable);
    });

    handle1.join().unwrap();
    handle2.join().unwrap();
}

我不明白为什么这段代码会编译。我在多个线程之间共享了变量 mutable ,甚至对其进行了变异。这里的内存究竟在幕后发生了什么?我们是否在静态内存中创建了多个指向同一个字符串的指针?我们是否在内存中放置了两个不同的静态字符串?我可以让两个线程从同一个不可变项中读取这一事实并不让我感到惊讶,但是让两个线程从一个可变变量中读取却确实如此。

请注意,即使线程 3 在 4 之前运行,4 也不会反射(reflect)线程 3 在其 println! 语句中设置的更新字符串。最后,由于我没有使用 &immutable 传递,这是否意味着该值被“移动”到每个线程而不是实际内存地址?

最佳答案



不,您已将同一静态字符串的引用复制到多个线程中。引用指向一个不能改变的常量静态字符串。只读引用是 Copy ,因此您可以将它们移动到多个闭包中。



字符串切片本质上是指向内存中字符串开头的指针以及长度。您的变量 mutableimmutable 仅包含这两部分信息,并且只有这些部分对于 mutable 是可变的。变量指向的实际字符串是不可变的。当将变量“移动”到闭包中时,它们实际上是被复制的,因为 &strCopy 。复制的唯一信息是指针和长度,而不是实际的字符串数据。您最终会得到多个指向同一只读内存的指针,这不允许任何数据竞争并符合 Rust 的内存安全规则。



您只修改指针的副本和长度。在线程 3 中,mutable 成为闭包局部的单独变量,您只需修改它。



变量 immutable 的类型为 &'static str ,所以它已经是一个引用; &immutable 将是对引用的引用。

关于multithreading - 为什么我可以在 Rust 中将静态 &str "move"转换为多个线程?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52771295/

10-12 00:35
查看更多