Rust Arc如何get_mut之后恢复由其他Arc副本读取的能力?



我想知道如何更改Arc中的值,然后使Arc的其他副本再次有效。

use std::sync::Arc;
use std::thread;
use std::error::Error;
use std::io;
use std::time::Duration;
#[derive(Debug)]
struct El {
n: i64,
}
fn main() -> io::Result<()> {
let mut a = Arc::new(El{n: 5});
let b = Arc::clone(&a);
let th = thread::spawn(move || {
println!(r#"Hello, World!"#);
thread::sleep(Duration::from_millis(1000));
println!("{:?}", b);
});
let mut c = Arc::get_mut(&mut a).unwrap();
c.n = 10;
drop(c);
drop(a);
th.join().expect("some errors occured");
Ok(())
}

这将导致在突变已经完成并且指针被删除的那一刻出现恐慌。如何解决?

你想在一个线程中写入Arc的内容,然后在另一个线程中读取它。在 Rust 中,值要么是共享可读的,要么是独占可写的。共享具有多个参照的弧。

您可以通过使用内部可变性来解决此问题,例如通过Arc<Mutex<El>>Arc<RwLock<El>>MutexRwLock通过阻止所有读取(直到写入完成(和只要存在读锁定就阻止所有写入来动态确保共享/独占约束。

例:

fn main() -> io::Result<()> {
let a = Arc::new(Mutex::new(El{n: 5}));
let b = Arc::clone(&a);
let th = thread::spawn(move || {
println!(r#"Hello, World!"#);
thread::sleep(Duration::from_millis(1000));
println!("{:?}", b.lock().unwrap());
});
a.lock().unwrap().n = 10;
drop(a);
th.join().expect("some errors occured");
Ok(())
}

我简化了代码以使问题显而易见:

use std::sync::Arc;
use std::thread;
use std::time::Duration;
#[derive(Debug)]
struct El {
n: i64,
}
fn main() {
let mut a = Arc::new(El { n: 5 });
let b = Arc::clone(&a);
let th = thread::spawn(move || {
thread::sleep(Duration::from_millis(1000));
println!("{:?}", b);
});
let _c = Arc::get_mut(&mut a).unwrap();
th.join().expect("some errors occurred");
}

仅当Arc::get_mutArc参数是唯一所有者时,才会起作用:在这种情况下,您可以收回数据的所有权。

在您的代码中,在这一行,生成的线程仍在运行,并且它仍然通过bab共享数据的所有权来保存共享数据。在收回数据的所有权之前,您必须首先确保删除b(请注意最后 2 行的交换(:

use std::sync::Arc;
use std::thread;
use std::time::Duration;
#[derive(Debug)]
struct El {
n: i64,
}
fn main() {
let mut a = Arc::new(El { n: 5 });
let b = Arc::clone(&a);
let th = thread::spawn(move || {
thread::sleep(Duration::from_millis(1000));
println!("{:?}", b);
});
th.join().expect("some errors occurred"); // b has been dropped
let _c = Arc::get_mut(&mut a).unwrap();
}

最新更新