一个可变借用和多个不可变借用

时间:2017-11-03 09:15:17

标签: multithreading concurrency rust ownership

我试图编写一个程序,该程序产生一个后台线程,不断地将数据插入到某个集合中。同时,我想继续从stdin获取输入,并检查该输入是否在线程正在运行的集合中。

这是一个简单的例子:

use std::collections::HashSet;
use std::thread;

fn main() {
    let mut set: HashSet<String> = HashSet::new();

    thread::spawn(move || {
        loop {
            set.insert("foo".to_string());
        }
    });

    loop {
        let input: String = get_input_from_stdin();

        if set.contains(&input) {
            // Do something...
        }
    }
}

fn get_input_from_stdin() -> String {
    String::new()
}

然而,由于所有权的原因,这不起作用。

我还是Rust的新手,但这似乎应该是可行的。我无法找到Arc s,Rc s,Mutex es等的正确组合来包装我的数据。

1 个答案:

答案 0 :(得分:6)

首先,请阅读Need holistic explanation about Rust's cell and reference counted types

这里有两个问题需要解决:

  1. 在线程之间共享所有权,
  2. 可变别名。
  3. 要分享所有权,最简单的解决方案是Arc。它要求其参数为Sync(可从多个线程安全访问),可以通过将其包含在SendMutex内来实现任何RwLock类型。

    为了在存在可变性的情况下安全地获取别名,MutexRwLock都可以正常工作。如果您有多个读者,RwLock可能会有额外的性能优势。由于你只有一个读者,所以没有意义:让我们使用简单的Mutex

    因此,您的类型为:Arc<Mutex<HashSet<String>>>

    下一个技巧是将值传递给闭包以在另一个线程中运行。值为已移动,因此您需要首先复制Arc然后传递克隆,否则您已移动原件而不能再访问​​它了。

    最后,访问数据需要通过借用和锁定......

    use std::sync::{Arc, Mutex};
    
    fn main() {
        let set = Arc::new(Mutex::new(HashSet::new()));
    
        let clone = set.clone();
        thread::spawn(move || {
            loop {
                clone.lock().unwrap().insert("foo".to_string());
            }
        });
    
        loop {
            let input: String = get_input_from_stdin();
    
            if set.lock().unwrap().contains(&input) {
                // Do something...
            }
        }
    }
    

    unwrap的调用是因为Mutex::lock返回Result;如果它被中毒,可能无法锁定Mutex,这意味着当它被锁定时发生恐慌,因此其内容可能是垃圾。

相关问题