Skip to content

Instantly share code, notes, and snippets.

@meqif
Last active October 3, 2017 11:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meqif/bd8a85654b230e8ecd1d3344fc707de9 to your computer and use it in GitHub Desktop.
Save meqif/bd8a85654b230e8ecd1d3344fc707de9 to your computer and use it in GitHub Desktop.
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