Here is what I did, unfortunately I still can't compile it successfully. I'm new to rust-lang.
I spent couple hours on it, I found it's difficult to be happy by coding in rust-lang.
Can any one post code that compiles?
use std::cell::RefCell;
use std::thread;
use std::sync::RwLock;
use std::sync::Arc;
use std::sync::Weak;
#[derive(Debug)]
struct Node {
value: i32,
parent: RwLock<Weak<Node>>,
children: RwLock<Vec<Arc<Node>>>,
}
fn main() {
let leaf = Arc::new(Node {
value: 3,
parent: RwLock::new(Weak::new()),
children: RwLock::new(vec![]),
});
println!("leaf parent = {:?}", leaf.parent.read().unwrap().upgrade());
let branch = Arc::new(Node {
value: 5,
parent: RwLock::new(Weak::new()),
children: RwLock::new(vec![Arc::clone(&leaf)]),
});
// let leaf = leaf.clone();
thread::spawn(move || {
*leaf.parent.write().unwrap() = Arc::downgrade(&branch);
}).join().unwrap();
println!("leaf parent = {:?}", leaf.parent.read().unwrap().upgrade());
}
You're almost there with the leaf.clone() you have commented out -- you just need to assign that to a variable that isn't leaf so you can move it into the closure without consuming the original Arc:
let leaf_clone = Arc::clone(&leaf); // instead of leaf.clone() which is ambiguous
thread::spawn(move || {
*leaf_clone.parent.write().unwrap() = Arc::downgrade(&branch);
}).join().unwrap();
This will print out None twice, because branch is also being moved in to the closure. When branch is dropped, there are no strong references remaining to keep the Arc<Node> alive, so upgrade() in the final line always returns None.
Presumably in a real program branch would be a clone of an Arc being stored somewhere else, so this wouldn't be a problem -- however just to make the example work, you can clone it and store the clone in an unused variable to keep it alive until the end of main.
let _branch = Arc::clone(&branch);
let leaf_clone = Arc::clone(&leaf);
thread::spawn(move || {
*leaf_clone.parent.write().unwrap() = Arc::downgrade(&branch);
}).join().unwrap();
@trentj Thank you very much. Obviously it's not a very efficient solution. It allocate memory twice. I just want to change the value of the pointer with second thread.
I feel like the language is on the verge of success.
Can any one tell me the rust-lang designer's email?
Here is my final code.
use std::cell::RefCell;
use std::thread;
use std::sync::RwLock;
use std::sync::Arc;
use std::sync::Weak;
#[derive(Debug)]
struct Node {
value: i32,
parent: RwLock<Weak<Node>>,
children: RwLock<Vec<Arc<Node>>>,
}
fn main() {
let leaf = Arc::new(Node {
value: 3,
parent: RwLock::new(Weak::new()),
children: RwLock::new(vec![]),
});
println!("leaf parent = {:?}", leaf.parent.read().unwrap().upgrade());
let branch = Arc::new(Node {
value: 5,
parent: RwLock::new(Weak::new()),
children: RwLock::new(vec![Arc::clone(&leaf)]),
});
modify_tree(&leaf, &branch);
println!("leaf parent = {:?}", leaf.parent.read().unwrap().upgrade());
}
fn modify_tree(leaf: &Arc<Node>, branch: &Arc<Node>) {
let leaf = Arc::clone(&leaf);
let branch = Arc::clone(&branch);
thread::spawn(move || {
*leaf.parent.write().unwrap() = Arc::downgrade(&branch);
}).join().unwrap();
}
Nope, the whole point of Rc and Arc is that they don't really copy memory when cloned, instead, they just increment a special counter (initially included / added to the allocated memory)