Last active
October 3, 2017 11:46
-
-
Save meqif/bd8a85654b230e8ecd1d3344fc707de9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::thread; | |
use std::sync::{Arc, RwLock}; | |
// Represents a reference to a node. | |
// This makes the code less repetitive to write and easier to read. | |
type NodeRef<T> = Arc<RwLock<_Node<T>>>; | |
// The private representation of a node. | |
struct _Node<T> { | |
inner_value: T, | |
adjacent: Vec<NodeRef<T>>, | |
} | |
// The public representation of a node, with some syntactic sugar. | |
struct Node<T>(NodeRef<T>); | |
impl<T> Node<T> { | |
// Creates a new node with no edges. | |
fn new(inner: T) -> Node<T> { | |
let node = _Node { inner_value: inner, adjacent: vec![] }; | |
Node(Arc::new(RwLock::new(node))) | |
} | |
// Adds a directed edge from this node to other node. | |
fn add_adjacent(&self, other: &Node<T>) { | |
self.0 | |
.write() | |
.expect("Failed to acquire a write lock on node") | |
.adjacent.push(other.0.clone()); | |
} | |
} | |
struct Graph<T> { | |
nodes: Vec<Node<T>>, | |
} | |
impl<T> Graph<T> { | |
fn with_nodes(nodes: Vec<Node<T>>) -> Self { | |
Graph { nodes: nodes } | |
} | |
} | |
fn main() { | |
// Create some nodes | |
let node_1 = Node::new(1); | |
let node_2 = Node::new(2); | |
let node_3 = Node::new(3); | |
// Connect some of the nodes (with directed edges) | |
node_1.add_adjacent(&node_2); | |
node_1.add_adjacent(&node_3); | |
node_2.add_adjacent(&node_1); | |
node_3.add_adjacent(&node_1); | |
// Add nodes to graph | |
let graph = Arc::new(Graph::with_nodes(vec![node_1, node_2, node_3])); | |
// Spawn a new thread that will print information about every node in the | |
// graph. | |
// The new scope makes this block more obviously different from the code | |
// surrounding it and lets us group variables that will be moved into the | |
// new thread, such as "graph". | |
let guard = { | |
let graph = graph.clone(); | |
let message = "Failed to acquire a read lock"; | |
thread::spawn(move || { | |
for _ in 0..10 { | |
// Show every node in the graph and list their neighbors | |
for node in &graph.nodes { | |
let node = node.0.read().expect(&message); | |
let value = node.inner_value; | |
let neighbours = node.adjacent | |
.iter() | |
.map(|n| n.read().expect(&message).inner_value) | |
.collect::<Vec<_>>(); | |
println!("node ({}) is connected to: {:?}", value, neighbours); | |
} | |
println!("-------------"); | |
// Give the main thread a chance to run | |
thread::yield_now(); | |
} | |
}) | |
}; | |
for _ in 0..10 { | |
// Update the value of every node in the graph | |
for node in &graph.nodes { | |
let mut node = node.0.write().expect("Failed to acquire a write lock"); | |
node.inner_value += 10; | |
} | |
// Give the other thread a chance to run | |
thread::yield_now(); | |
} | |
// Wait for the other thread to end | |
guard.join().expect("Error joining thread"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment