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

dro*_*te7 4 rust

我想知道如何更改内部的值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(())
}
Run Code Online (Sandbox Code Playgroud)

当突变已经完成并且指针被丢弃时,这会导致恐慌。如何解决呢?

Cor*_*onA 8

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

您可以通过使用内部可变性来解决这个问题,例如viaArc<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(())
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*ios 5

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

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");
}
Run Code Online (Sandbox Code Playgroud)

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

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

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();
}
Run Code Online (Sandbox Code Playgroud)

  • @dronte7 嗯,这个问题并不清楚。您想将一些数据从生成的线程传输到主线程吗?只需使用一个通道即可。 (2认同)