在Rust中分享线程之间的可变变量

时间:2013-07-26 17:02:50

标签: multithreading rust

是否可以在Rust中的多个线程之间共享一个可变变量?鉴于以下内容:

fn main() {

    let mut msg = "Hi";
    // ...
    msg = "Hello, World!";

    do spawn {
        println(msg);
    }

    do spawn {
        println(msg);
    }

}

我收到此错误:

error

变量只需要对生成的线程只读。变量必须是可变的,因为我真正想要做的是在多个线程之间共享一个HashMap。据我所知,除非它是可变的,否则无法填充HashMap。即使有办法做到这一点,我仍然有兴趣知道如何完成这样的事情。

谢谢!

4 个答案:

答案 0 :(得分:9)

此限制将在该语言的未来版本中删除。也就是说,您可以在第一个let msg = msg;之前使用do spawn解决此问题。这将将值msg 移动到一个不可变的位置,从而有效地改变其可变性。

答案 1 :(得分:3)

在共享字符串“Hello,World!”的情况下,你只需要将变量移回一个不可变的位置(例如,“let mut msg = .....; let msg = msg; “)。

可能你也想避免为接收它的每个线程制作一个单独的hashmap副本,但在这种情况下你还要把它放在ARC(原子引用计数包装器)中,您可以在extra::arc中找到。

答案 2 :(得分:3)

“一般”的答案(关于在共享时保持哈希表是可变的)是它不是直接可能的; Rust专门设计用于禁止共享可变状态以避免某些类型的错误并保护某些类型的安全(以及其他原因)。

但是,可以创建类似于共享可变哈希表的东西。想象一下,单个任务有一个可变的哈希表。您可以编写代码,以便其他任务可以向其发送消息,主要是“更新哈希表以便5映射到18”或“告诉我7个映射到”。

这种间接完成了什么?首先,通过将值复制到消息中,不可能让另一个任务践踏你正在阅读的整个内存(一个很大的安全问题),其次,通过间接编写代码,程序员会更清楚什么是和不是原子操作;程序员将知道不要期望关于散列表内容的两个连续消息不一定是关于散列表的相同版本,这个假设完全有效(至少在Rust中,由于一些其他限制)关于两个连续读取来自未共享的,可变的哈希表。

答案 3 :(得分:2)

如果变量可以是原子变量,则可以使用Arc进行引用计数和原子类型。 Arc是一个参考计数器,其作用与具有以下功能的语言中的垃圾收集器非常相似:

use std::sync::atomic;
use std::sync::Arc;

fn main() {
    let arc_num = Arc::new(atomic::AtomicU32::new(1337));
    let arc_num_clone = Arc::clone(&arc_num);

    let _get_borrowed_clone = move || {
        return arc_num_clone.load(atomic::Ordering::Relaxed);
    };

    arc_num.store(4242, atomic::Ordering::Relaxed)
}

playground

同样,您不能使用原子类型,在这种情况下,可以使用ArcMutex

use std::sync::{Arc, Mutex};

fn main() {
    let arc_num = Arc::new(Mutex::new(1337));
    let arc_num_clone = Arc::clone(&arc_num);

    let _get_borrowed_clone = move || {
        let out = *arc_num_clone.lock().unwrap();
        return out;
    };

    *arc_num.lock().unwrap() = 4242;
}

Read more about how this code works

如果您想进一步了解这两种方法之间的区别,请阅读Is there any difference between "mutex" and "atomic operation"?