如何使用 Arc 在线程之间共享可变对象?
How do I share a mutable object between threads using Arc?
我正在尝试使用 Arc
在 Rust 中的线程之间共享一个可变对象,但我收到此错误:
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
的文档说:
Shared references in Rust disallow mutation by default, and Arc
is no exception: you cannot generally obtain a mutable reference to something inside an Arc
. If you need to mutate through an Arc
, use Mutex
, RwLock
, or one of the Atomic
types.
您可能需要 Mutex
与 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
文档中抄袭的。
How can I use shared_stats after the for? (I'm talking about the Stats object). It seems that the shared_stats cannot be easily converted to Stats.
从 Rust 1.15 开始,。另请参阅我的其他解决方案的附加答案。
[A comment in the example] says that there is no multithreading. Why?
因为我糊涂了! :-)
在示例代码中,thread::spawn
的结果(一个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
,一个旧的,删除的API,加入时已删除。抱歉造成混淆!
对于一些社论,我建议完全避免可变性:
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 模式。请注意,没有线程需要任何可变性,这一切都发生在主线程中。
我正在尝试使用 Arc
在 Rust 中的线程之间共享一个可变对象,但我收到此错误:
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
的文档说:
Shared references in Rust disallow mutation by default, and
Arc
is no exception: you cannot generally obtain a mutable reference to something inside anArc
. If you need to mutate through anArc
, useMutex
,RwLock
, or one of theAtomic
types.
您可能需要 Mutex
与 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
文档中抄袭的。
How can I use shared_stats after the for? (I'm talking about the Stats object). It seems that the shared_stats cannot be easily converted to Stats.
从 Rust 1.15 开始,
[A comment in the example] says that there is no multithreading. Why?
因为我糊涂了! :-)
在示例代码中,thread::spawn
的结果(一个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
,一个旧的,删除的API,加入时已删除。抱歉造成混淆!
对于一些社论,我建议完全避免可变性:
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 模式。请注意,没有线程需要任何可变性,这一切都发生在主线程中。