【问题标题】:One mutable borrow and multiple immutable borrows一个可变借用和多个不可变借用
【发布时间】:2018-04-15 23:12:55
【问题描述】:

我正在尝试编写一个程序来生成一个后台线程,该线程不断地将数据插入到某个集合中。同时,我想继续从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 的新手,但这似乎应该是可能的。我只是找不到Arcs、Rcs、Mutexes 等的正确组合来包装我的数据。

【问题讨论】:

标签: multithreading concurrency rust ownership


【解决方案1】:

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


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

  1. 线程间共享所有权,
  2. 可变别名。

要共享所有权,最简单的解决方案是Arc。它要求其参数为Sync(可从多个线程安全访问),这可以通过将任何Send 类型包装在MutexRwLock 中来实现。

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

因此,您的类型是:Arc&lt;Mutex&lt;HashSet&lt;String&gt;&gt;&gt;

下一个技巧是将值传递给闭包以在另一个线程中运行。该值是moved,因此您需要首先制作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 返回一个ResultMutex如果中毒了,可能无法锁定,这意味着锁定时发生了恐慌,因此其内容可能是垃圾。

【讨论】:

  • 作为Mutex "Trait Implementations" 文档,您不能将any 类型换行以获得Sync;你需要包装一个Send 类型。
  • @Stefan:对!我什至没有想过有人试图将非发送类型发送到另一个线程,但明确一点肯定更好。
猜你喜欢
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多