本文介绍了如何使用Arc在线程之间共享可变对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Arc在Rust中的线程之间共享一个可变对象,但出现此错误:

I'm trying to share a mutable object between threads in Rust using Arc, but I get this error:

error[E0596]: cannot borrow data in a `&` reference as mutable
  --> src/main.rs:11:13
   |
11 |             shared_stats_clone.add_stats();
   |             ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

这是示例代码:

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

fn main() {
    let total_stats = Stats::new();
    let shared_stats = Arc::new(total_stats);

    let threads = 5;
    for _ in 0..threads {
        let mut shared_stats_clone = shared_stats.clone();
        thread::spawn(move || {
            shared_stats_clone.add_stats();
        });
    }
}

struct Stats {
    hello: u32,
}

impl Stats {
    pub fn new() -> Stats {
        Stats { hello: 0 }
    }

    pub fn add_stats(&mut self) {
        self.hello += 1;
    }
}

我该怎么办?

推荐答案

Arc 的文档说:

Arc's documentation says:

您可能希望将MutexArc结合使用:

You will likely want a Mutex combined with an Arc:

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

struct Stats;

impl Stats {
    fn add_stats(&mut self, _other: &Stats) {}
}

fn main() {
    let shared_stats = Arc::new(Mutex::new(Stats));

    let threads = 5;
    for _ in 0..threads {
        let my_stats = shared_stats.clone();
        thread::spawn(move || {
            let mut shared = my_stats.lock().unwrap();
            shared.add_stats(&Stats);
        });
        // Note: Immediately joining, no multithreading happening!
        // THIS WAS A LIE, see below
    }
}

这很大程度上来自Mutex文档.

This is largely cribbed from the Mutex documentation.

从Rust 1.15开始,有可能找回价值.另请参阅我的其他解决方案的答案.

As of Rust 1.15, it's possible to get the value back. See my additional answer for another solution as well.

因为我很困惑! :-)

Because I got confused! :-)

在示例代码中,为thread::spawn的结果( JoinHandle )被立即删除,因为它没有存储在任何地方.放下手柄后,线程会分离,并且可能会结束,也可能永远不会结束.我将它与 JoinGuard 混淆了,删除了加入的的API.抱歉造成混乱!

In the example code, the result of thread::spawn (a JoinHandle) is immediately dropped because it's not stored anywhere. When the handle is dropped, the thread is detached and may or may not ever finish. I was confusing it with JoinGuard, a old, removed API that joined when it is dropped. Sorry for the confusion!

对于一些社论,我建议完全避免可变性:

For a bit of editorial, I suggest avoiding mutability completely:

use std::{ops::Add, thread};

#[derive(Debug)]
struct Stats(u64);

// Implement addition on our type
impl Add for Stats {
    type Output = Stats;
    fn add(self, other: Stats) -> Stats {
        Stats(self.0 + other.0)
    }
}

fn main() {
    let threads = 5;

    // Start threads to do computation
    let threads: Vec<_> = (0..threads).map(|_| thread::spawn(|| Stats(4))).collect();

    // Join all the threads, fail if any of them failed
    let result: Result<Vec<_>, _> = threads.into_iter().map(|t| t.join()).collect();
    let result = result.unwrap();

    // Add up all the results
    let sum = result.into_iter().fold(Stats(0), |i, sum| sum + i);
    println!("{:?}", sum);
}

在这里,我们保留对JoinHandle的引用,然后等待所有线程完成.然后,我们收集结果并将其全部累加.这是常见的 map-reduce 模式.请注意,没有线程需要任何可变性,所有这些都发生在主线程中.

Here, we keep a reference to the JoinHandle and then wait for all the threads to finish. We then collect the results and add them all up. This is the common map-reduce pattern. Note that no thread needs any mutability, it all happens in the master thread.

这篇关于如何使用Arc在线程之间共享可变对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 19:33
查看更多